Skip to content

v6.0.0.beta1

Pre-release
Pre-release

Choose a tag to compare

@nbulaj nbulaj released this 22 Jul 13:25
3de27a9

Please make sure you read the Upgrade guides and changelog below before the update since this version includes breaking changes.

  • [#1816] Fix: redirect unauthorized_client errors per RFC 6749 Section 4.1.2.1; validate redirect_uri before client_supports_grant_flow to prevent open redirect
  • [#1867] Fix: use access_denied instead of invalid_client for resource_owner_authorize_for_client validation per RFC 6749 Section 4.1.2.1. invalid_client is a token endpoint error (Section 5.2), not an authorization endpoint error.
  • [#1838] Add OAuth 2.0 Authorization Server Metadata endpoint (RFC 8414) served at /.well-known/oauth-authorization-server. The response is built from your Doorkeeper configuration and advertises the authorization, token, revocation and (when token introspection is enabled) introspection endpoints, supported scopes, response/grant types and PKCE code challenge methods. Two new config options are available: issuer (defaults to the request base URL) and custom_metadata (a Hash merged into the response, e.g. to advertise an OIDC userinfo_endpoint). The controller/response use the RFC 8414 "Metadata" naming so they don't collide with a future OpenID Connect Discovery (.well-known/openid-configuration) implementation. Endpoints disabled through skip_controllers are omitted from the response instead of raising a route-generation error.
  • [#1839] Send client credentials in the request body (not the query string) in the token endpoint specs, per RFC 6749 §2.3.1. Test-only change: the *_endpoint_url helpers now return a path plus a matching *_endpoint_params builder so flow specs post credentials through the body.
  • [#1840] Introduce a pluggable client authentication registry (RFC 6749 §2.3).
    • New client_authentication config option declares which methods are accepted and in which order. Built-in strategies: client_secret_basic, client_secret_post and none.
    • Custom strategies can be registered with Doorkeeper::ClientAuthentication.register.
    • [BREAKING] Client credentials are no longer read from the query string — send them in the request body or via HTTP Basic. This applies to every endpoint that authenticates clients: token, revocation and introspection.
    • [BREAKING] The none strategy rejects requests that carry a non-blank Authorization header. A common casualty is a public client POSTing to /oauth/revoke with a body client_id while still sending its Authorization: Bearer <token> header — drop the header from that request.
    • [BREAKING] The Doorkeeper::OAuth::Client::Credentials class methods .from_request, .from_basic and .from_params are removed — extensions extracting credentials from a request should register a client authentication method instead.
    • Deprecated: the client_credentials option — use client_authentication instead.
    • Deprecated: the Doorkeeper::OAuth::Client::Credentials constant itself — it remains as an alias of Doorkeeper::ClientAuthentication::Credentials (the plain uid/secret struct).
    • See the Upgrade Guide for detailed breaking changes, deprecations and migration steps.
  • [#1841] Reject requests that use more than one client authentication method (RFC 6749 §2.3: "The client MUST NOT use more than one authentication method in each request") with an invalid_request error instead of silently using the first match. The request payload is validated against every registered method before the configured one is selected, so a client sending e.g. both Basic and body credentials is rejected even when only one of those methods is enabled. This applies to every endpoint that authenticates clients — token, revocation and introspection. Only real authentication mechanisms count: a bare client_id (the none method) is not a mechanism of its own, and deprecated client_credentials callable extractors never count towards the limit (they keep the historical first-extractor-wins selection).
  • [#1842] [BREAKING] force_pkce now requires PKCE for all clients, including confidential ones, in line with the OAuth 2.0 Security BCP (RFC 9700) and OAuth 2.1. Previously confidential clients were exempt. If you enable force_pkce and have confidential clients that do not yet send a code_challenge/code_verifier, their authorization requests will start to be rejected.
  • [#1845] Fix NameError when the config option DSL (Doorkeeper::Config::Option) is extended into a class that does not define self.builder_class. The guard raised Doorkeeper::MissingConfigurationBuilderClass, a constant that was never defined, so callers saw uninitialized constant instead of the intended message. The error is now defined as Doorkeeper::Errors::MissingConfigurationBuilderClass (a DoorkeeperError) and referenced correctly.
  • [#1846] Document and pin with regression specs that a scope parameter sent to the token endpoint is ignored for the authorization_code grant (RFC 6749 §4.1.3 does not define one): the access token always inherits the scopes of the authorization grant, and the response reports the actual granted scope. No behavior change.
  • [#1847] Fix Doorkeeper.config.enabled_grant_flows (and calculate_grant_flows) not listing the refresh_token grant flow when use_refresh_token is configured, so consumers (e.g. RFC 8414 metadata) no longer need to append it manually — the built-in metadata endpoint now relies on this too. The flow is no longer duplicated in token_grant_flows when refresh_token is also listed in grant_flows explicitly, a configuration-time warning is logged when grant_flows enables refresh_token without use_refresh_token (no refresh tokens would ever be issued), and the initializer template documents the flow.
  • [#1848] Derive token_endpoint_auth_methods_supported in the RFC 8414 metadata response from the effective client authentication configuration (including a deprecated client_credentials-only setup) instead of hardcoding the default methods. Servers that customize client_authentication (including extension-registered methods like private_key_jwt) now see their metadata reflect what the server actually accepts; unregistered names are not advertised.
  • [#1849] Support RFC 9207 (Authorization Server Issuer Identification): when issuer is configured, the iss parameter is added to the authorization responses redirected back to the client (successful and error responses alike) and authorization_response_iss_parameter_supported is advertised in the server metadata. Clients that parse the authorization redirect will start seeing the new iss parameter. A configured issuer that is not RFC-compliant (not an https URL, or containing a query/fragment) now logs a warning at boot, as does a path-bearing issuer, which RFC 8414 clients would not discover through Doorkeeper's root-only well-known metadata route.
  • [#1850] Fix reuse_access_token returning a refresh token that doesn't match the request: token reuse now requires the candidate's refresh token presence to match what the request asks for, in both directions. A request that expects a refresh token (e.g. use_refresh_token enabled) no longer reuses a token issued without one (previously the refresh token was silently omitted), and a request that does not expect one no longer reuses a token that carries one (previously an unrequested refresh token was returned, reachable via a per-request refresh_token_enabled callable). The requirement participates in the token matching itself, so an older matching token that satisfies it is still reused; a fresh token is created only when none does. API change for ORM extensions: matching_token_for and find_matching_token now take an optional block (&filter) that a token must satisfy to count as a match — extensions overriding either method must accept the block and honor it (accept and yield).
  • [#1851] Fix duplicate query parameter in the authorization callback when a client's registered redirect_uri already contains a parameter with the same name as a response parameter (e.g. state). The redirect query was merged with string keys on one side and symbol keys on the other, so a collision emitted the parameter twice (?state=fixed&code=...&state=user); the response parameter now overrides the registered one and appears exactly once. A blank response parameter (e.g. no state sent with the request) leaves the registered parameter untouched, per RFC 6749 §3.1.2.
  • [#1852] Fix the pkce_code_challenge_methods config validator using line anchors (^/$) instead of string anchors (\A/\z), so a multi-line value such as "plain\ngarbage" passed validation and was retained as a (never-matching) challenge method instead of being rejected and reset to the default.
  • [#1853] Fix reuse_access_token reusing a token that was created with custom_access_token_attributes values when the new request doesn't specify any custom attributes. Such requests now only match tokens without custom attributes.
  • [#1854] Fix the RFC 8414 metadata endpoint raising ActionController::UrlGenerationError (HTTP 500) when use_doorkeeper configures a custom controller whose namespace depth differs from doorkeeper/metadata (e.g. controllers tokens: "custom_tokens").
  • [#1855] Perform the fallback secret upgrade-on-access write (plain → hashed token or application secret) through the primary database role, so enable_multiple_database_roles setups no longer attempt the write on a read replica when the lookup happens in a request routed to the reading role.
  • [#1857] Pin with regression specs that a + between scopes in a form-encoded token request is decoded as a space (so scope=public+write refreshes fine), while a percent-encoded literal + (%2B) names a single scope and is rejected when unknown, per RFC 6749 §3.3. Test-only change, closes [#1686].
  • [#1859] Pin with regression specs that a refresh token bound to an expired access token can be revoked (fixed by [#1744]) and that the revoked refresh token is rejected at the token endpoint afterwards. Test-only change, closes [#1671].
  • [#1860] Fix introspection of refresh tokens (RFC 7662): a refresh token bound to an expired access token now introspects as active: true, matching the token endpoint which still accepts it. The introspection response for a presented refresh token no longer includes the paired access token's token_type and exp. Fixes [#1858].
  • [#1862] Document that with reuse_access_token enabled token matching considers only the application, resource owner, scopes and custom token attributes — separate authorization grants for the same combination intentionally share one access token — and pin the behavior with a regression spec. Docs/test-only change, closes [#1693].
  • [#1864] Fix custom_access_token_attributes values being dropped when the authorization goes through the consent screen: the approve/deny forms now carry the custom attributes as hidden fields, and the pre-authorization JSON (api_only mode) includes them so custom consent UIs can send them back.
  • [#1869] Improve test coverage
  • [#1870] Fix: raise the intended Doorkeeper::Errors::TokenGeneratorNotFound / UnableToGenerateToken (instead of a confusing NameError) when application_secret_generator is misconfigured.