Skip to main content

v26.3.15

v26.3.15

Oathkeeper adopts shared HTTP metrics and adds per-rule access decisions

Oathkeeper uses the shared Ory HTTP metric schema. It also exposes ory_oathkeeper_access_decisions_total, which reports allowed requests, authentication failures, authorization failures, and pipeline errors by rule ID. Access decisions are independent of login redirects and upstream response codes.

Breaking changes

For Oathkeeper dashboards and alerts, replace service with app and status_code with code. The request label is replaced by endpoint, which contains API router patterns such as /rules/{param} and /decisions/ and is empty for proxy traffic. The app values remain oathkeeper-api and oathkeeper-proxy. HTTP metrics also include version, hash, and buildTime. Metric names retain the configured prefix. Health requests are now included.

serve.prometheus.hide_request_paths and serve.prometheus.collapse_request_paths are deprecated and have no effect. Update path filters to use router patterns or the new per-rule counter.

In Oathkeeper, Kratos, Hydra, and Keto, the requests_statuses_total metric's method labels now follow the same normalization as other shared HTTP metrics: recognized methods use lowercase values, and other methods use other. Oathkeeper applies this normalization to all HTTP metrics.

Unsupported methods use other instead of unknown across all shared HTTP metrics. Update queries that filter on the previous method label.

Require user authorization for verifiable credentials

POST /credentials issues credentials only to access tokens that represent an authenticated end user and carry both the openid and userinfo_credential_draft_00 scopes. The same requirement applies to nonce priming requests. Both scopes must be granted explicitly; a wildcard grant does not satisfy the requirement.

Breaking changes

A token that does not carry both scopes receives scope_not_granted with HTTP 403. Scope names are matched exactly, so a scope that differs in case does not satisfy the requirement.

To use this draft endpoint, request both scopes in the authorization flow and grant both during consent. The token endpoint returns c_nonce_draft_00 only for tokens that meet these requirements. Other access token issuance is unaffected.

Device authorization errors are shown on the error page

An OAuth 2.0 device authorization grant has no redirect URI, so an error at the device verification endpoint had nowhere to go and was written to the browser as a JSON response body. The most common case is a user who denies the request at the login or consent screen: they were left looking at raw JSON.

Those errors are now sent to the error page configured under urls.error, carried in the error and error_description query parameters, the same way an authorization request that has no valid redirect URI already is. A denial arrives there under the error code the rejection named, and the device still receives access_denied on its next poll.

If your error page distinguishes the errors it receives, expect device verification errors on it now. GET /oauth2/device/verify no longer answers any error with a JSON body: every error path redirects to the error page instead. The device polling behavior is unchanged.

A rejection also reads as one sentence now. Account Experience rejects a login or consent request with error_description set to "The request was rejected. The application was not granted access to your account." and no longer sends error_hint, so OAuth 2.0 clients of a redirect-based flow receive that text in their error redirect.

Hydra gains a FIPS 140-3 build

Ory Enterprise License releases now include a dedicated FIPS build of Hydra (hydra_oel_fips_<version>_<os>_<arch>) next to the standard build. The FIPS build uses the Go Cryptographic Module and starts with GODEBUG=fips140=on by default, so Hydra's cryptography runs through the FIPS 140-3 validated module. The standard build is unchanged as long as it runs without GODEBUG=fips140=on.

A few things need attention before you switch. The FIPS build seals transient payloads with AES-256-GCM instead of XChaCha20-Poly1305, so the two builds cannot read each other's login, consent, device, and logout flows, verifiable credential nonces, unredeemed authorization codes, or admin API page tokens; plan a stop-then-start cutover. hydra serve refuses to start unless secrets.system, secrets.cookie, and secrets.pagination are each set explicitly with their own active secret, and unless oauth2.hashers.algorithm is pbkdf2bcrypt hashes client secrets outside the validated module, though client secrets already hashed with it keep verifying. And because AES-GCM draws a random nonce per payload, regular rotation of secrets.system is mandatory in FIPS mode.

For the full picture — obtaining and verifying the build, the required configuration, the rotation budget, and what each cipher changes to — see FIPS 140-3 build.

TLS configuration and unix socket recovery in Hydra, Keto and Kratos

A configured certificate is now the only switch for TLS in all three services. serve.<endpoint>.tls.enabled is deprecated but still accepted so that an existing configuration keeps loading, but it has no effect. Each service logs a warning at startup naming the key to remove. To serve plain HTTP behind a proxy that terminates TLS, remove the certificate rather than the flag.

Hydra and Kratos also pick up two fixes from the shared serve configuration:

  1. configuring only one half of a certificate pair is now a startup error instead of a listener that silently falls back to plain HTTP
  2. a unix socket left behind by an unclean shutdown is replaced instead of blocking the next start.

Because the three services now configure their endpoints identically, the documentation for it is one page: Serving the APIs. It replaces the separate Hydra and Kratos HTTPS pages, which now redirect to it.