DATE:
AUTHOR:
Ory Team
Ory Network Ory Hydra Ory Kratos Ory Keto Ory Oathkeeper Ory Polis Ory Enterprise License

Ory Network, Ory Hydra, Ory Kratos, Ory Keto, Ory Oathkeeper, Ory Polis v26.3.15 released

DATE:
AUTHOR: Ory Team

Ory Network

Set technical, business, security, and privacy contacts for a workspace

You can now register who Ory should reach for each workspace. Open the workspace settings in the Ory Console and add a contact for one or more of the technical, business, security, and privacy responsibilities. A contact is either a current workspace member or an email address, and one contact can hold several responsibilities.

Once a contact is set, Ory sends communication for that topic to that address. For example, security notices go to the security contact and privacy or data processing updates go to the privacy contact. Workspaces without contacts keep receiving communication as before.

All workspace members can view contacts. Only members who can manage workspace settings can add, change, or remove them. Being a contact grants no Console permissions, and removing a member also removes that member's contacts from the workspace.


This is now available on Ory Network.


Ory Hydra

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.


This is now available on Ory Network, for the Ory Enterprise License, and will be part of the next Ory Open Source release.


Ory Kratos

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.

Sensitive values are now encrypted by default

Kratos used to default to the no-op cipher, which stored sensitive values in plaintext — OIDC provider tokens, and DeviceAuthn PIN secrets in Ory Enterprise License deployments. ciphers.algorithm now defaults to [xchacha20-poly1305, noop]: new values are encrypted with XChaCha20 Poly1305, and values already stored in plaintext keep decrypting until they are written again. An unknown algorithm no longer falls back to plaintext; it fails closed, and every encrypt or decrypt returns an error.

Breaking changes

secrets.cipher is now required. Kratos refuses to start unless it holds at least one 32-character secret. Add it to your configuration before you upgrade — the current version accepts the setting and ignores it, so the rollout is:

  1. Add a 32-character secrets.cipher.

  2. Roll out this version.

To keep storing these values in plaintext, set ciphers.algorithm: noop explicitly. This provides no confidentiality or integrity and is not recommended. secrets.cipher is required either way.

During the rolling upgrade, instances still running the previous version can't read values that upgraded instances have already encrypted. If you can't tolerate that window, set ciphers.algorithm: noop explicitly in step 1 and remove it once every instance runs the new version. Both instances then agree on the algorithm throughout the rollout, and the switch happens on a configuration change rather than across the deployment.

Changing the algorithm

ciphers.algorithm also accepts an ordered list. The first algorithm encrypts new values; the rest only decrypt older ones, and each value is re-encrypted with the first algorithm on its next write. This mirrors secrets.cipher key rotation, one level up, so you can change algorithms without re-encrypting existing data and without downtime. noop is only valid as the last entry, because it decodes any value and would shadow the algorithms after it.

Import identities faster with all-or-nothing batches

PATCH /admin/identities accepts a new with_partial_inserts field in the request body. It defaults to true, which is the existing behavior: each identity is imported on its own, and an identity that conflicts with one that already exists is reported individually while the rest of the batch is still imported.

Set it to false to import the batch as a single unit. The whole batch is then written in one transaction, which is considerably faster. In a cluster whose regions are 250 ms apart, a batch of 10 identities that took 2.2 seconds takes 0.4 seconds, and a batch of 1000 that took 7 seconds takes 2.5. In exchange, a single conflict fails the request with 409 Conflict and no identity from the batch is created.

Use it when you expect the batch to contain no duplicates. That is the case when you import from a database that already enforces the same unique constraints, or when you have validated the data beforehand. You can also use it optimistically: send the batch with with_partial_inserts set to false, and repeat the request with true if it returns 409 Conflict.

The response does not say which identities conflicted, because none of them were imported. The retry with with_partial_inserts set to true imports every identity that does not conflict and reports a per-identity error for the ones that do.

Support IdP-initiated SAML login

Enterprise users can now start a login from their identity provider's app launcher (for example the Okta or Azure AD dashboard) and land in your application with a valid Ory session.

When an identity provider posts an unsolicited SAML response, Ory Polis validates it and redirects the browser to a new Kratos entry point with a single-use authorization code. Kratos starts a regular SP-initiated login flow — with the usual state, CSRF, and PKCE protections — and forwards the code as a code_hint to the Polis authorize endpoint. Polis consumes the hint and completes the flow immediately, without a second round-trip to the identity provider.

Standalone Ory Polis already supports IdP-initiated SAML login through its direct redemption flow. This change adds the Kratos side: an entry point that folds the unsolicited response into a regular SP-initiated Kratos login, wired together with Polis through the code_hint.

To enable it on Ory Network, turn on the "IdP-initiated login" toggle in the SAML provider settings in Ory Console. Ory then points the SAML connection's default redirect URL at the entry point automatically.

To enable it on a self-hosted Ory deployment that runs Kratos and Polis together:

  1. Set idp_initiated_login_enabled: true on the SAML (jackson) provider in your Kratos configuration.

  2. Point the Polis SAML connection's defaultRedirectUrl at https://<your-project>/self-service/methods/saml/idp-initiated/<provider>.

  3. Run Polis with IDP_ENABLED=true.

IDP_ENABLED is the deployment-wide switch. A connection follows it unless it sets idpInitiatedLoginEnabled explicitly: true always allows IdP-initiated login for that connection and false always blocks it. On Ory Network the switch stays off and the Console toggle sets the per-connection flag, so no deployment-wide change is needed.

The code hint is single use, expires with the code store TTL, and is only valid for the exact connection it was issued for. SP-initiated codes cannot be used as hints. If a hint is invalid or already consumed, the user is sent through the regular SP-initiated redirect instead — usually completing silently against the identity provider's existing session.

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.


This is now available on Ory Network, for the Ory Enterprise License, and will be part of the next Ory Open Source release.


Ory Keto

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.

Keto can serve its APIs over HTTPS

Every Keto endpoint - read, write, OPL syntax and metrics - can now terminate TLS itself. Point Keto at a certificate and key, either as file paths or as base64-encoded PEM:

serve:
  read:
    tls:
      cert:
        path: /etc/keto/tls/tls.crt
      key:
        path: /etc/keto/tls/tls.key

Configuring a certificate is what turns TLS on for an endpoint. If the TLS configuration is incomplete or incorrect, Keto fails to start instead of silently falling back to insecure HTTP.

When you configure the certificate through path, Keto reloads it automatically as it changes on disk, so certificate rotation needs no restart. gRPC and HTTP clients keep working over the TLS port.

TLS is off by default and the listen addresses are unchanged, so existing deployments continue to serve plain HTTP.

Listening on a unix socket

Every endpoint can also listen on a unix socket instead of a TCP port. Set the host to a unix: path and control who may connect through the file permissions:

serve:
  read:
    host: unix:/var/run/keto/read.sock
    socket:
      owner: keto
      group: keto
      mode: 384 # 0600

Connecting to a unix socket requires write permission on the socket file, so mode is the access control for the endpoint. It defaults to 493 (0755), which lets only the owner connect. Keto removes the socket file when it shuts down.

A unix socket endpoint cannot terminate TLS, because the socket permissions are the access control and there is no host name for a client to verify. Configuring both is rejected at startup rather than silently serving one of them.

Configuration that is now rejected

Two configurations that Keto used to accept and silently ignore are now rejected at startup: a write_listen_file without the file:// scheme, and a tls.cert or tls.key that sets both path and base64. Neither ever took effect, so correct the value and Keto starts as before.

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.


This is now available for the Ory Enterprise License and will be part of the next Ory Open Source release.


Ory Oathkeeper

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.


This is now available for the Ory Enterprise License and will be part of the next Ory Open Source release.


Ory Polis

DynamoDB deployments now honor the page limit when listing records

When DB_ENGINE is dynamodb, endpoints that list records by an index returned every matching record in one response and ignored the requested page size. They now return at most DB_PAGE_LIMIT records per call, which matches every other database engine.

DynamoDB cannot skip records, so pageOffset is ignored on this engine. When you page through connections, directory users or groups, or SSO traces with the management API, read the pageToken from the response and pass it back to fetch the next page.

SCIM is the exception, because it has no page token. The SCIM endpoints an identity provider calls page with startIndex, which DynamoDB ignores, so on this engine an identity provider reads the first DB_PAGE_LIMIT users or groups of a directory and cannot reach the rest. Do not run directory sync on DynamoDB with directories larger than DB_PAGE_LIMIT.

Index rows are also written in batches now, and any row DynamoDB reports as unwritten is retried. Under heavy write throttling a record could previously be saved but stay unreachable through one of the indexes that point at it.

Listing SSO connections now returns all of them

Reading the SSO connections for a tenant and product returned only as many as a single database read yields, which DB_PAGE_LIMIT caps and defaults to 50. A tenant with more connections than that saw a short list with nothing to indicate records were missing, and the same limit applied when reading connections for several tenants at once, when filtering by strategy, and when looking up connections by identity provider entity ID.

All of these now read through to the end of the list. If you have more connections than DB_PAGE_LIMIT under one tenant and product, expect the list to be longer than before.

Support IdP-initiated SAML login

Enterprise users can now start a login from their identity provider's app launcher (for example the Okta or Azure AD dashboard) and land in your application with a valid Ory session.

When an identity provider posts an unsolicited SAML response, Ory Polis validates it and redirects the browser to a new Kratos entry point with a single-use authorization code. Kratos starts a regular SP-initiated login flow — with the usual state, CSRF, and PKCE protections — and forwards the code as a code_hint to the Polis authorize endpoint. Polis consumes the hint and completes the flow immediately, without a second round-trip to the identity provider.

Standalone Ory Polis already supports IdP-initiated SAML login through its direct redemption flow. This change adds the Kratos side: an entry point that folds the unsolicited response into a regular SP-initiated Kratos login, wired together with Polis through the code_hint.

To enable it on Ory Network, turn on the "IdP-initiated login" toggle in the SAML provider settings in Ory Console. Ory then points the SAML connection's default redirect URL at the entry point automatically.

To enable it on a self-hosted Ory deployment that runs Kratos and Polis together:

  1. Set idp_initiated_login_enabled: true on the SAML (jackson) provider in your Kratos configuration.

  2. Point the Polis SAML connection's defaultRedirectUrl at https://<your-project>/self-service/methods/saml/idp-initiated/<provider>.

  3. Run Polis with IDP_ENABLED=true.

IDP_ENABLED is the deployment-wide switch. A connection follows it unless it sets idpInitiatedLoginEnabled explicitly: true always allows IdP-initiated login for that connection and false always blocks it. On Ory Network the switch stays off and the Console toggle sets the per-connection flag, so no deployment-wide change is needed.

The code hint is single use, expires with the code store TTL, and is only valid for the exact connection it was issued for. SP-initiated codes cannot be used as hints. If a hint is invalid or already consumed, the user is sent through the regular SP-initiated redirect instead — usually completing silently against the identity provider's existing session.


This is now available on Ory Network, for the Ory Enterprise License, and will be part of the next Ory Open Source release.


Ory Elements and Ory Terraform

No significant changes in this release.

Powered by LaunchNotes