# OpenID Connect flows, response modes and claims

This page is for operators and realm administrators. It covers what the authorization endpoint of a realm
(`/realms/<realm>/oauth2/authorize`) accepts, and which claims the tokens and userinfo carry. The behaviour follows
OpenID Connect Core 1.0, OAuth 2.0 Multiple Response Type Encoding Practices and OAuth 2.0 Form Post Response Mode.

## Response types

| `response_type` | Flow | Available to |
|---|---|---|
| `code` | Authorization code (recommended; PKCE for public clients) | every client with the `authorization_code` grant |
| `id_token`, `id_token token` | Implicit (Core §3.2) | clients with the **implicit** grant only |
| `code id_token`, `code token`, `code id_token token` | Hybrid (Core §3.3) | clients with the **implicit** grant only |

Discovery (`response_types_supported`, `grant_types_supported`) lists the implicit and hybrid response types and
the `implicit` grant only in a realm where a client can use them. That is a realm where a client has the implicit
grant, or where Dynamic Client Registration may register it.

### The implicit and hybrid flows are off by default

These flows return tokens through the browser, so OAuth 2.1 and FAPI no longer recommend them. They are there for
OpenID Connect relying parties that cannot use the code flow. To switch them on for one client:

- **Console:** open *Clients → the client → Credentials* and tick **Implicit and hybrid flows (legacy)**.
- **Admin API:** add `implicit` to the client's `grantTypes`.

HelixIAM refuses the switch (`400`, field `grantTypes`) in these cases:

| Code | Why |
|---|---|
| `implicitNeedsCode` | The client must also have the `authorization_code` grant. Both flows are built on the authorization endpoint's code issuance. |
| `implicitNotFapi` | The client requires a signed request object, certificate-bound access tokens or a JARM response mode. FAPI allows the code flow only. |
| `implicitHighAssurance` | The realm uses the HIGH key-custody profile. |

**Dynamic Client Registration.** A registration that asks for a response type with `id_token` or `token` (or for
the `implicit` grant) needs the `implicit` grant. The realm administrator must allow that grant for registration
(*Provisioning → Dynamic Client Registration → allowed grant types → Implicit and hybrid (legacy)*). It is never
allowed by default. Such a client is registered with the `authorization_code` grant as well, and the registration
response reports both.

### What the authorization endpoint checks and returns

- **`redirect_uri`:** must be one of the client's registered redirect URIs, compared exactly.
- **`nonce`:** required whenever an ID token comes from the authorization endpoint (Core §3.2.2.1, §3.3.2.11).
- **Scope:** `openid` is required.
- **Response mode:**
  - `fragment` is the default.
  - `form_post` is also accepted.
  - `query` is refused (`invalid_request`): tokens are never put in a query string.
- **Errors:** sent back in the same response mode as a success would be.
- **The ID token from the authorization endpoint:**
  - carries `nonce`, `at_hash` with an access token and `c_hash` with a code;
  - the hash is that of the ID token's signing algorithm;
  - it carries the standard claims of the granted scopes.
- **The access token from the authorization endpoint:**
  - lives at most 5 minutes;
  - no refresh token is ever issued with it.
- **Hybrid flow:** the code is redeemed at the token endpoint as usual, with PKCE when the client sent a
  `code_challenge`.
- **Implicit flow:** the code is never sent to the client.
- **Behind a reverse proxy:** these responses carry the tokens in the `Location` header of the redirect. With many
  claims that header exceeds the 4–8 KB response-header buffer some proxies default to, and the proxy answers 502:
  - nginx: `proxy_buffer_size 32k; proxy_buffers 8 32k;`
  - ingress-nginx: the annotation `nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"`
- **Everything else is the same as the code flow:** sign-in, `prompt`, `max_age`, consent, MFA, the session
  binding (`sid`, `auth_time`, `acr`) and the audit trail.

## Response modes

| `response_mode` | For |
|---|---|
| `query` | `code` (the default) |
| `fragment` | implicit and hybrid (the default) |
| `form_post` | every response type (OAuth 2.0 Form Post Response Mode) |

With `form_post`, the authorization endpoint answers with a page whose form POSTs the response parameters to the
redirect URI. The page submits itself with a script served by HelixIAM, and its content security policy only allows
a form to the redirect URI's origin.

## Claims

The standard claims of the `profile`, `email`, `address` and `phone` scopes (OpenID Connect Core §5.4) are released
only when that scope is granted. A claim named in the `claims` request parameter (§5.5) is released too:

- a claim named under `id_token` goes into the ID token;
- a claim named under `userinfo` comes from userinfo.

The values have the JSON types of §5.1:

- `email_verified` and `phone_number_verified` are booleans;
- `updated_at` is seconds since the epoch, the last change of the account;
- `address` is one JSON object.

Claims outside these scopes (custom attributes released by the claim mapping, roles, organizations) are not
affected.

## See also

- [OIDC client settings](../manage/oidc-client-settings.md): JWK Set by value, signed userinfo, request URIs, session management, login initiation and the logo, policy and terms links
- [OIDC clients](../manage/oidc-clients.md) and [Client scopes & claims](../manage/scopes-and-claims.md)
- [OpenID Connect conformance-suite run](../compliance/oidc-conformance.md)
- [Upgrading from 1.1.0-rc.13 to 1.1.0-rc.14](../operations/upgrade-1.1.0-rc13-rc14.md)
