New Ory Agent Security is now live! Claim your complimentary test drive. Get Started!

Skip to main content

v26.3.18

v26.3.18​

Require sign-in with a specific OpenID Connect provider from the after web_hook response​

A login after web_hook with response.parse enabled can now return {"force_credential": {"method": "oidc", "provider": "<provider id>"}} to require that session to be signed in with one specific OpenID Connect provider. Use it when an external check, such as a bank ID broker or an ID verification provider, has to confirm who the user is before they can continue. One response can raise the AAL, update the identity, and require a provider at the same time; the requirements are independent.

The requirement is stored on the session, so it outlasts the login that created it. While it is pending, /sessions/whoami, GET /sessions, and the settings flow answer with 403 Forbidden and the new error ID session_credential_required, whose error.details.redirect_browser_to points at a refresh login. That login offers only the required provider's sign-in button. Signing in there clears the requirement; signing in with any other credential does not. The user does not need an account at the provider yet: the required sign-in links the provider account, and the tokens it issued, to the identity. Because it can link an account, the required sign-in takes the same Authenticator Assurance Level as the settings flow, so a session that still owes a second factor is sent to it first.

This is off by default and uses the existing feature_flags.webhook_response_directives feature flag, or kratos_feature_flags_webhook_response_directives on the project for Ory Network. While the flag is off, a force_credential field in a web_hook response is ignored. Once it is on, oidc is the only supported method, and a value that names another method or no provider fails the login rather than being silently dropped. A provider that is not configured or is scoped to an organization fails the login with a configuration error, and so do two web_hooks on the same position that require different providers. On a web_hook at another position the directive is logged and ignored.

Webhook failures now carry an error ID​

Webhook request timeouts now return error.id: webhook_timeout. Failed requests, including exhausted retries on HTTP 429 or 5xx other than 501, return webhook_request_failed. A 4xx response other than 429, or a 501 response, returns webhook_unexpected_status unless response parsing is enabled and the body contains valid validation messages; those messages still appear as validation errors.

Status codes and messages are unchanged except for parsed 4xx responses other than 429, and parsed 501 responses, that have no valid validation messages. These now return 502 Bad Gateway with webhook_unexpected_status instead of a generic parsing error. For API registration flows, the previous response was HTTP 400 with an internal-error body.

These IDs don't cover every webhook failure. Empty or malformed HTTP 200 responses with response parsing enabled still fail without a webhook error ID.

Webhooks and claims hooks can read the caller's location​

Every Kratos webhook now receives the caller's approximate location as ctx.location, with the fields city, region, country, latitude and longitude. It's available on all self-service webhooks and on the password migration hook.

ctx.location and all of its fields are always present, so a template written against the Ory Network keeps working on a self-hosted deployment. Kratos derives the values from the Cf-* request headers, so on a self-hosted deployment the strings are empty and the coordinates are null unless your own proxy sets those headers.

Filling the fields is your responsibility. Ory ships no geolocation database, so the values come from a reverse proxy in front of Ory that can resolve an IP address to a location — for example nginx with the ngx_http_geoip2 module and a MaxMind database. Set Cf-Ipcity, Cf-Region-Code, Cf-Ipcountry, Cf-Iplatitude and Cf-Iplongitude.

Set all five, including any you can't resolve: nginx's proxy_set_header replaces whatever the client sent, and it omits a header whose value is empty. A header you leave alone arrives from the client unchanged, and you must not use these fields for authorization decisions.

The webhooks guide has a worked nginx configuration.

The session JWT claims hook is a payload change rather than a template binding: its request body gains a location object. Existing endpoints that ignore unknown fields are unaffected.