Skip to content

Upgrading from 1.1.0-rc.13 to 1.1.0-rc.14

This release comes from a self-run of the OpenID Foundation conformance suite against every OpenID Connect OP certification profile (OpenID Connect conformance-suite run). Most of it is new and off until you use it. Two changes reach every installation: tokens now carry the standard profile claims only for the scopes granted, and userinfo no longer returns the access token's own claims. Check your relying parties for those two before you upgrade.

Before you upgrade (summary)

  • Migrations V192 to V195 add nullable columns to service_provider_oauth: jwks (V192); logo_uri, policy_uri, tos_uri, userinfo_signed_response_alg, request_uris (V193); session_management (V194); initiate_login_uri (V195). Migration V196 adds a change-notification trigger on realm_provisioning_config. All catalog-only: no table rewrite, no value touched.
  • Relying parties that use the email address, name or other profile claims must ask for the scope (below). Most do already; check the ones that send only scope=openid.
  • Relying parties that read token claims from userinfo (iss, aud, exp, scope, client_id, sid, acr, amr, ...) must read them from the ID token or the access token instead (below).
  • Nothing else changes until you configure it: the implicit and hybrid flows and session management are off for every client, and the new client fields are empty.

Tokens carry profile, email, address and phone claims only for the scopes granted

  • What changed. An ID token or access token carries the claims of the profile, email, address and phone scopes (OpenID Connect Core 1.0 §5.4) only when that scope was granted, or when the claim is named in the claims request parameter (§5.5) for that token's channel (id_token for the ID token, userinfo for the access token) and belongs to a scope the client is registered for and that was granted: by the user's consent, or, for a client without a consent screen, by its registration. Before, every token carried the user's whole standard profile whatever was requested. Userinfo is built from the access token, so it follows the same rule. Unchanged: realm_access, resource_access, organizations, claims released by protocol mappers, workload-identity tokens and the tokens a client or agent gets as itself (client_credentials).
  • Who is affected.
  • Relying parties that request only openid and read email, name, preferred_username or other profile claims: those claims are now absent.
  • Token-exchange on-behalf-of tokens: they carry these claims only when their scope includes the scope the claims belong to.
  • The admin console: its helix-console client was seeded with openid,profile. It is now seeded with openid,profile,email, the server adds email to the existing helix-console client of every realm at start-up, and the console requests openid profile email. Nothing to do.
  • What to do. Make each relying party request the scopes whose claims it uses, typically openid profile email (many already do, for example Nextcloud user_oidc), and make sure each client is registered for those scopes. For token exchange, request the scope in the exchange.

Userinfo returns claims about the end-user only

  • What changed. Userinfo (OpenID Connect Core 1.0 §5.3.2) returns sub, the released standard claims, claims-parameter claims, realm_access, resource_access, organizations, verified claims and the BSN where released. It no longer returns the access token's own claims: iss, aud, exp, iat, nbf, jti, scope, client_id, sid, azp, auth_time, nonce, acr, amr, cnf, act, may_act. For a client with userinfoSignedResponseAlg set, the response is a JWT (application/jwt) signed with the realm's ID-token key at that algorithm, with iss and aud (the client) besides the end-user claims; for every other client it stays JSON.
  • Who is affected. Relying parties or gateways that read token metadata (expiry, scopes, session id, acr/amr) from the userinfo response. realm_access is still there.
  • What to do. Read those values from the ID token (sid, auth_time, acr, amr) or from token introspection (exp, scope, client_id).

Standard claims in their JSON types

  • What changed (OpenID Connect Core 1.0 §5.1, §5.1.1): updated_at is a number (seconds since the epoch), phone_number_verified a boolean, and address one JSON object with formatted, street_address, locality, region, postal_code and country. Before, updated_at and phone_number_verified were strings and the address members were flat claims (address.locality, ...). A stored value that is no such value is left out rather than sent mistyped.
  • Who is affected. Code that parsed updated_at or phone_number_verified as strings, or read address.* as separate claims.
  • What to do. Read them as the specification types them; read the address members from the address object.

Dynamic Client Registration defaults and metadata

  • What changed.
  • A registration without scope gets openid, plus offline_access for a client of the refresh_token grant (RFC 7591 §2 lets the server choose the default). Before, such a client got no scope, and its scope=openid request failed with invalid_scope.
  • A response that issues a client_secret carries client_secret_expires_at: 0 (the secret does not expire; RFC 7591 §3.2.1); without a secret it is absent.
  • Accepted and returned: jwks (mutually exclusive with jwks_uri), id_token_signed_response_alg, userinfo_signed_response_alg, logo_uri, policy_uri, tos_uri, request_uris and initiate_login_uri.
  • Response types with id_token or token need the implicit grant, which registration may add only when the realm administrator allows that grant for registration (never by default).
  • Who is affected. Clients that register themselves. A client registered without scope that needs more than openid (and offline_access) gets nothing further by default.
  • What to do. Nothing for existing registrations. A registering client that needs profile or email sends them in scope.

New client settings, all off or empty by default

  • What changed. Per client, in the admin API, Dynamic Client Registration, the realm export/import and the console (OpenID Connect flows and OIDC client settings):
  • The implicit and hybrid flows (id_token, id_token token, code id_token, code token, code id_token token): the implicit grant type, off by default and only together with authorization_code. Refused (400, field grantTypes) for a client with a FAPI setting (a required signed request object, certificate-bound access tokens, a JARM mode) and in a realm with the HIGH key-custody profile. The HIGH rule holds at use too: in a HIGH realm the authorization endpoint never answers an implicit or hybrid request, whatever a client has stored, and a move to HIGH is refused (409, code implicitFlowClients, naming the clients) while a client of the realm has the implicit grant. An ID token from the authorization endpoint needs a nonce; an access token from it lives at most 5 minutes and never comes with a refresh token, and a second use of a hybrid flow's code revokes it with the code's other tokens.
  • jwks (a JWK Set by value, instead of jwksUrl), logoUri, policyUri, tosUri, userinfoSignedResponseAlg, requestUris (request objects by reference, fetched only from a registered URI), sessionManagement (session_state and the check-session iframe, off by default) and initiateLoginUri.
  • Who is affected. Nobody until a setting is used.
  • What to do. Turn the implicit or hybrid flow on only for a relying party that cannot use the code flow, and put the proxy setting below in place first.

Discovery states more

  • What changed. /.well-known/openid-configuration now lists:
  • scopes_supported: openid, profile, email, address, phone; and address in claims_supported;
  • request_parameter_supported, request_uri_parameter_supported and require_request_uri_registration, all true, with request_object_signing_alg_values_supported (RS256);
  • userinfo_signing_alg_values_supported (those of RS256, PS256, ES256 the realm publishes ID-token keys for);
  • response_modes_supported: query and form_post, plus fragment in a realm that advertises the implicit and hybrid flows (response_mode=form_post is now honoured for every response type, errors included; before it was ignored);
  • frontchannel_logout_supported and frontchannel_logout_session_supported: true;
  • check_session_iframe, only in a realm where a client uses session management;
  • the implicit and hybrid response types and the implicit grant, only in a realm where a client has that grant or registration may add it.
  • These per-realm facts come from the configuration cache (V196 keeps it current), so a warm discovery request still reads nothing from the database.
  • Who is affected. Relying parties that configure themselves from discovery; they may now choose form_post or request objects by reference.
  • What to do. Nothing.

Implicit and hybrid responses need a larger proxy response-header buffer

  • What changed. Implicit and hybrid responses carry the ID token and access token in the Location header of the redirect. With many claims that header exceeds the 4 KB default response-header buffer of ingress-nginx (4 to 8 KB in other proxies), and the proxy answers 502.
  • Who is affected. Installations that turn the implicit or hybrid flow on for a client.
  • What to do. Behind ingress-nginx, set the annotation nginx.ingress.kubernetes.io/proxy-buffer-size: "32k" (chart: ingress.annotations."nginx\.ingress\.kubernetes\.io/proxy-buffer-size"="32k"); behind nginx, proxy_buffer_size 32k; proxy_buffers 8 32k;. The chart does not set it by default.

A client assertion without client_id is accepted

  • What changed. A private_key_jwt or client_secret_jwt request that leaves out client_id (OPTIONAL with an assertion, RFC 7521 §4.2) is accepted on every endpoint that authenticates clients: the client is the assertion's iss when it equals its sub (RFC 7523 §3). Before, it was refused with invalid_request. The assertion is verified exactly as before (signature against the client's keys, audience, lifetime, single use); one that names no single client is invalid_request.
  • Who is affected. Clients that send only the assertion.
  • What to do. Nothing.

See also