Skip to main content
Some OIDC clients send requests in a shape that departs from the RFC. Veriqa is strict and rejects them — the right default, except when you cannot fix the client: someone else’s plugin, an off-the-shelf CMS, a vendor build. A compatibility quirk is a named relaxation of the request form, enabled for a single client. Every quirk is narrow, off by default, and ships with a removal condition stated up front: once the upstream defect is fixed, the key is retired along with its handler.
A quirk is a behavior branch, not a setting. Enable one only when a specific client genuinely cannot send a conformant request, and retire it as soon as the removal condition is met. Veriqa reports every enabled quirk with a startup warning in the log.

Why per client, not globally

A relaxation enabled globally weakens the check for every application — including those that send conformant requests, and those that will appear in the configuration tomorrow. Strictness stops being a property of the deployment and becomes a property of its weakest participant. So a quirk is addressed by ClientId: the client with the broken plugin gets the relaxation, every other client stays strict. That also keeps the relaxation visible — the configuration says which application is allowed what beyond the RFC.

Enabling

Enabling takes two steps: listing the quirk on the client is not enough, the deployment gate has to be open as well. While the gate is closed, the client’s quirk set is intersected with the empty core-level set and no relaxation applies.
appsettings.json
The two steps exist so that a single client’s configuration cannot weaken the check on its own: the overall ceiling belongs to whoever owns the deployment, the specific application to its client entry.

A profile instead of a list of keys

Rather than writing the keys out one by one, you can name a profile — the engine and plugin you actually run. A profile expands into the very same keys and passes the same validation, the same gate and the same ceiling: it is a shorthand, not a second mechanism.
appsettings.json
A profile and an explicit list can be combined — the keys are unioned. An unknown profile name stops startup with a message listing the allowed names, exactly as an unknown quirk key does: a typo cannot quietly leave the relaxation switched off. A profile may carry relaxations of the request form and nothing else. Nothing that changes claims can be enabled by one: switching on compatibility with a broken client must not also change what the token says about who signed in.

Disabling

Remove the key from that client’s CompatibilityQuirks — the relaxation stops applying after the next restart. To drop every quirk in the deployment at once without touching client entries, close the gate: CompatibilityQuirksAllowApplicationOverride: false. Nothing needs disabling to begin with: the default is off for everyone. A fresh deployment applies no quirk until you open the gate and list a key explicitly.

What Veriqa reports at startup

  • A quirk is in effect — a warning listing “client → enabled quirks”. This noise is intended: an enabled relaxation must not be silent.
  • A quirk is listed but not in effect — a warning with the reason. If the gate is closed it says so, and opening the gate is the fix. If the gate is open and the set is still empty, the gate is not the cause: the client entry never reached the resolver, most often because a second entry with the same ClientId shadows it.
  • An unknown key — startup does not continue: the configuration picks a key from a closed registry, and a typo here would mean a silently unapplied relaxation. The message lists the allowed keys. The comparison is case-sensitive — Drop-Scope-On-Code-Exchange is rejected just like a typo.
The configuration selects a key, never a type or an assembly name: no reflection is ever performed on a configured string. The right to edit configuration does not grant code execution inside the identity provider.

Quirk registry

drop-scope-on-code-exchange

What it does. Drops the scope parameter from a token request made with grant_type=authorization_code. Why. RFC 6749 §4.1.3 does not define scope in that request, and the strict check rejects it as invalid_request. On a code exchange the submitted scope has no effect anyway — the granted set comes from the authorization code — so dropping the parameter is equivalent to the client never having sent it. No rights are widened. Who needs it. The openid-connect-generic plugin for WordPress puts scope into the code exchange request. The symptom: sign-in reaches the code exchange and fails with
In WordPress that response is not what the integrator sees: the plugin returns the browser to the site login page and puts the error text into the address — wp-login.php?login-error=invalid_request&message=The+'scope'+parameter+is+not+valid+in+this+context. With the quirk enabled the same request passes the form check, and the log gains an entry about the dropped parameter — carrying the ClientId and the dropped value. No site-side change is needed: sign-in works on the stock plugin, with no patch installed on the site. What is untouched. The grant_type=refresh_token path: there scope is allowed by RFC 6749 §6 and narrows the granted rights. The quirk leaves that path alone — narrowing rights is both legal and useful. Removal condition. The upstream fix oidc-wp/openid-connect-generic#497 is released and rolled out by the integrators running the plugin. After that the key is retired along with its handler. While the issue is open, the quirk is needed.

drop-resource-parameter

What it does. Drops the resource parameter (RFC 8707) from the authorization request and from the token request. Why. Veriqa registers no resources, so the strict check rejects any value of that parameter with invalid_target and the sign-in fails before it starts. Nothing here consumes the parameter: with no registered resources the granted rights come from the scopes alone, so dropping it yields exactly the token a client that never sent it would receive. The quirk grants no audience and narrows none — it is not support for resource indicators. Who needs it. The auth_oidc plugin for Moodle keeps the Microsoft Entra ID dialect it was written for and sends resource on every request, in its generic mode too; there is no setting to switch that off. The symptom: sign-in stops at the authorization request with
With the quirk enabled the same request passes the form check, and the log gains an entry about the dropped parameter — carrying the ClientId and the dropped value. What is untouched. The default. Without the key enabled for that specific client_id, resource is rejected with invalid_target. Removal condition. Moodle’s auth_oidc stops sending resource in its generic (non-Entra) mode. There is no upstream ticket for that.

Next

Configuration reference

Every key, client ones included.

Preparing for production

What to check before shipping to production.