# Upgrading from 1.1.0-rc.14 to 1.1.0-rc.15

This release adds the FAPI 2.0 security profile, FAPI 2.0 Message Signing (JAR and JARM) and mutual TLS (RFC 8705)
([FAPI 2.0 & mutual TLS](../integration/fapi2.md)). Most of it is off until you use it: the security profile is a
per-realm setting (default *Standard*), and mutual TLS needs configuration. Three changes reach every installation;
check them before you upgrade.

## Before you upgrade (summary)

- **Migrations V197 to V199** are catalog-only: a column with a constant default and a `NOT VALID` check on the realm
  custody settings (V197, `security_profile`), nullable columns on `service_provider_oauth` (V198
  `tls_client_auth_*`, V199 `authorization_signed_response_alg`) and a constant-default column for
  `require_signed_request_object` (V199). No table rewrite, no backfill.
- **Forwarded client certificates are off by default (breaking).** `HELIX_FAPI_CLIENT_CERT_HEADER` is now empty, and
  the header is honoured only from the peers in the new `HELIX_FAPI_CLIENT_CERT_TRUSTED_PROXIES` (Helm
  `fapi.clientCertTrustedProxies`), no longer from every `HELIX_TRUSTED_PROXIES` peer. If you terminate mutual TLS at
  a proxy and use `tls_client_auth`, `self_signed_tls_client_auth` or certificate-bound tokens, set both: the header
  name, and the addresses of the proxy that verifies client certificates (the ingress controller, never the console
  pods). The chart refuses `ingress.mtls.enabled` or `fapi.clientCertHeader` without `fapi.clientCertTrustedProxies`.
  Without them, discovery advertises no mutual-TLS method and no `tls_client_certificate_bound_access_tokens`.
- **Clients that send DPoP proofs now get DPoP-bound tokens.** Before, an access token requested with a DPoP proof
  was issued as a Bearer token. Such clients must present the token with `Authorization: DPoP` and a proof.
- **Authorization responses carry `iss`** (RFC 9207) in every response mode. Relying parties that reject unknown
  parameters on the redirect URI must accept it (RFC 6749 §4.1.2 says to ignore unknown parameters).

## Other behaviour changes

- A request without client authentication at the token, PAR, revocation or introspection endpoint is `401` with the
  JSON error `invalid_client` (it was a redirect or an empty `401`).
- An expired `request_uri` is `invalid_request_uri` at the client's redirect URI; a used one, or another client's,
  shows the error page "Sign-in request no longer valid".
- A client with certificate-bound tokens that presents no certificate is refused (`invalid_request`), never given an
  unbound token.
- Dynamic Client Registration updates (`PUT /connect/register/{id}`, RFC 7592) cannot weaken a client
  (certificate-bound tokens, signed request objects, the authentication method); only an administrator lowers them.
- A request object's `client_id` must be the outer `client_id` at the authorization endpoint
  (`invalid_request_object`).
- A path that percent-encodes an unreserved character (`/oauth2/%61uthorize`) is `400 invalid_request` on every path.
- `tls_client_auth` refuses a certificate whose key usage lacks `digitalSignature` or whose extended key usage names
  neither `clientAuth` nor `anyExtendedKeyUsage` (`invalid_client`).
- A client's JARM `authorization_signed_response_alg` must be one the realm has an active key for (`noActiveKey`).
- The sign-in page has a *Cancel* while an authorization request is pending; the client gets `error=access_denied`.

## Turning FAPI 2.0 on

*Realm settings → Security* in the console, or `PUT /admin/realms/{realm}/settings/security-profile` with
`{"securityProfile": "FAPI2"}`. Public and client-secret clients of that realm can no longer authenticate there; the
console lists them before you confirm. The master realm cannot use it. See [FAPI 2.0 & mutual TLS](../integration/fapi2.md).

## See also

- [FAPI 2.0 & mutual TLS](../integration/fapi2.md)
- [FAPI 2.0 conformance-suite run](../compliance/fapi2-conformance.md)
- [Upgrades & migrations](upgrades.md)
