6.0.0.beta2
Pre-release
Pre-release
Please make sure you read the Upgrade guides
and changelog below before the update since this version includes breaking changes.
- [#1865] Revoke the token issued for an authorization code when the code is exchanged more than once, per RFC 6749 §4.1.2 / §10.5. Active when the
oauth_access_grants.access_token_idcolumn exists: new installs get it from the generated migration, existing apps can add it withrails generate doorkeeper:grant_reuse_revocation. Closes [#1713]. - [#1871] [BREAKING]
redirect_uriis now compared to the registered redirect URIs with the simple string comparison required by RFC 6749 §3.1.2.3 (the RFC 8252 §7.3 loopback port exception is kept). Clients relying on the previous lenient matching must send the exact registered URI, closes [#1718]. - [#1874] Fix
force_pkcerequiring acode_challengefrom response types that never issue an authorization code (e.g.token, or an OIDC extension'sid_token/id_token token). PKCE (RFC 7636) protects the authorization code exchange, so for code-less response types there is no token-endpoint step where acode_verifiercould ever be checked — such requests were rejected over a parameter that cannot be validated.force_pkcenow only enforces the challenge for response types that issue a code (codeand code-carrying hybrid types such ascode id_token). - [#1876] Fix: reject a non-string
scopeparameter (e.g.scope[a]=b, which Rack parses into a Hash) withinvalid_request(RFC 6749 §3.3) instead of an unhandled 500.Scopes.from_stringnow raisesErrors::InvalidScopeParameterfor a non-string argument — turned intoinvalid_requestby the token endpoint'srescue_from, so every grant type is covered — and the authorization endpoint rejects it up front in pre-authorization validation. The crash was reachable unauthenticated, before client authentication. - [#1877] Fix: let the
noneclient authentication strategy match a request whoseAuthorizationheader carries a Bearer token. A bearer credential authorizes access to the endpoint itself (e.g. a bearer-protected introspection endpoint per RFC 7662 §2.1, or a revocation request) rather than authenticating the client, so it must not suppress the public-clientnonestrategy when the client identifies itself with a bodyclient_id. Any other non-blankAuthorizationvalue — Basic, or aBearerwith no token — is still treated as header-based client authentication and continues to bypassnone. The 6.0.0.beta1 workaround of dropping theAuthorizationheader from such a request is no longer needed. - [#1878] Fix: the loopback redirect URI exception (RFC 8252 §7.3) now varies by port only, not by userinfo. The port was cleared with
URI#port=, which on Ruby >= 4.0 also drops the userinfo, sohttp://attacker@127.0.0.1/cbmatched a registeredhttp://127.0.0.1/cb. The match is now made component-by-component. The destination host is always the loopback interface, so this was not a cross-origin open redirect, and non-loopback hosts were never affected. - [#1879] Fix: with
reuse_access_tokenenabled, replaying an authorization code no longer revokes an access token that another grant still shares. The single-use revocation added in [#1865] followed the grant'saccess_token_id, which a reused token shares across grants, so a replay could collaterally revoke a token another valid session still held. The revocation now skips a token referenced by another grant and only reaches one unique to the replayed code; a token unique to the code is still revoked as before. - [#1881] Fix:
Doorkeeper::ApplicationsControllerno longer 500s oncreate/update/destroyinapi_onlymode, whereActionController::APIprovides noflash. Confiningflashto the HTML path is not sufficient on its own, because a client that does not name JSON explicitly still negotiates its way into that path — an absentAcceptheader and a browser-like list such asapplication/json, text/plain, */*both resolve totext/html, and a bare*/*resolves to the first registered format — soapi_onlymode now pins the response format to JSON. - [#1883] Internal: merge
CHANGELOG.mdwith git'suniondriver, so two pull requests that each add an entry no longer conflict on the line above "Please add here". - [#1884] Fix:
/oauth/introspectand/oauth/revokeextend the token lookup across both token types when the lookup bytoken_type_hintfinds nothing (RFC 7662 §2.1 / RFC 7009 §2.1), so a wrong hint no longer hides a token the server knows about ([#1882]) - [#1885] Index
oauth_access_grants.access_token_idin the migration templates: since [#1879] the code-replay revocation filters access grants by that column, the "never used to filter queries" premise behindindex: falseno longer holds. - [#1886] Add support for Resource Indicators for OAuth 2.0 (RFC 8707). Clients can include a
resourceparameter in authorization and token requests to indicate the target protected resource(s). The authorization server validates resource URIs, enforces audience restriction on tokens, and includesaudin introspection responses. Enable by configuringresource_indicator_validatorwith a callable. Requires newresourcecolumns on access grants and tokens — runrails generate doorkeeper:resource_indicatorsto add the migration. - [#1887] [test] Pin that a requested non-default scope reaches the authorization grant and the exchanged token, and that the authorization strategy shares the controller's pre-authorization — the mismatch reported in [#1576] does not reproduce. Test-only change, closes [#1576].
- [#1888] Document custom grant flow registration (
Doorkeeper::GrantFlow.register) in the README with a SAML 2.0 bearer assertion (RFC 7522) walkthrough, and pin URN-shaped custom grant types with an end-to-end request spec. Docs/test-only change, closes [#764]. - [#1890] [test] Pin that the authorization endpoint answers
invalid_redirect_urifor a client registered without a redirect URI (allow_blank_redirect_uri), whether or not the request supplies one — the behavior required by RFC 6749 §3.1.2.3. Test-only change, closes [#1682]. - [#1898] Fix: with
reuse_access_tokenenabled, theclient_credentialsgrant no longer reuses a token whoseresourcediffers from the one requested (RFC 8707), so the audience restriction the client asked for is always applied. Follow-up to [#1886]. - [#1899] Document the client authentication methods registry (
Doorkeeper::ClientAuthentication.register) in the README with a walkthrough for registering a custom method, and pin it with an end-to-end request spec. Docs/test-only change, closes [#1894]. - [#1891] Fix: an authorization request carrying a
redirect_urifor a client registered without one (redirect_uriisnilunderallow_blank_redirect_uri) now answersinvalid_redirect_uriinstead of crashing with an unhandled 500. - [#1896] Add an opt-in
private_key_jwtclient authentication method (RFC 7523 / OIDC Core §9, requires thejwtgem >= 2.7) that verifies assertions against the client's published public keys —jwks/jwks_uriattributes you define on your Application model, the latter fetched with an SSRF-hardened HTTP client. The jti replay guard and the fetched-JWKS cache are process-local by default and can be replaced with shared stores via theprivate_key_jwt_replay_guard/private_key_jwt_jwks_cacheconfig options. Part of [#1875]. - [#1901] [test] Pin the answered behaviors behind [#984], [#1554], [#1600], [#1663], [#1759] and [#1787] with regression specs — the built-in client authentication methods, the unmodified echo of long
statevalues, DB persistence with custom token generators, refresh token rotation/expiry semantics and the introspection asymmetry. Test-only change, closes those issues along with [#1291], [#1756] and [#1764]. - [#1902] Fix: requests that omit
scopenow compute the same default scopes at the authorization and token endpoints (Scopes#common, symmetric). With dynamic scopes enabled, a scope pattern in eitherdefault_scopesor the application's scopes grants the matching concrete scope at both endpoints, closes [#1889]. - [#1903] Fix:
revoke_previous_client_credentials_tokenno longer revokes a client's live access token issued for a differentresource([#1886]), so a client can keep one audience-restricted token per resource server. - [#1905] [test] Cover
private_key_jwtclient authentication on theclient_credentialsgrant, the one flow where an assertion is the client's only credential end to end. Test-only change.