# RP-Initiated Logout, form-encoded (RP-Initiated Logout 1.0 §2)

`POST /end_session`

Identical to the GET form in every respect except where the parameters
travel. Preferred by relying parties that do not want an `id_token_hint` in
a URL.

## Authorization

None: this endpoint does not take API credentials.

This endpoint reads the browser session from the `Cookie` header: The request Cookie header; the interactive login / pending-auth session cookie, and the browser marker a sign-in is recognized by, are read from it.

This endpoint is rate limited; it answers `429` when a limit is hit.

## Headers

- `Cookie` (string, optional): The request Cookie header; the interactive login / pending-auth session cookie, and the browser marker a sign-in is recognized by, are read from it.

## Request body (`application/x-www-form-urlencoded`, optional)

The RP-Initiated Logout parameters (RP-Initiated Logout 1.0 §2), carried in a form body instead of the query string. Identical in meaning to the GET form's query parameters; sending them here keeps an id_token_hint — which identifies the user — out of browser history, access logs and Referer headers.

- `id_token_hint` (string, optional): A previously issued ID token identifying the session to end. Constraints: at most 8192 characters.
- `logout_hint` (string, optional): Constraints: at most 1024 characters.
- `client_id` (string, optional): Constraints: at most 256 characters.
- `post_logout_redirect_uri` (string, optional): Must exactly match a pre-registered post-logout redirect URI. Constraints: at most 2048 characters.
- `state` (string, optional): Constraints: at most 1024 characters.
- `ui_locales` (string, optional): Constraints: at most 256 characters.

## Responses

### 200 OK

The front-channel logout page (see the GET form).

Content type: `text/html`

Headers:
- `Set-Cookie` (array of strings)
- `Cache-Control` = `no-store`
- `Pragma` = `no-cache`
- `Content-Security-Policy` = `default-src 'none'; style-src 'unsafe-inline'; frame-src https: http:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'`: Locks the logout page down to inline styles and cross-origin frames.

### 302 Found

Redirect to the validated post_logout_redirect_uri (or the hosted UI), with the session cookie cleared.

Headers:
- `Location` (string)
- `Set-Cookie` (array of strings)
- `Cache-Control` = `no-store`
- `Pragma` = `no-cache`

### 429 Too Many Requests

Too many requests.

Content type: `application/problem+json`

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

### Error

OAuth2 error response (RFC 6749 §5.2).

Content type: `application/json`

Headers:
- `Cache-Control` = `no-store`
- `WWW-Authenticate` (string)
- `DPoP-Nonce` (string)

An OAuth2 error response (RFC 6749 §5.2). `iss` (RFC 9207) is present on authorization-endpoint error responses so clients can detect mix-up.

- `error` (string, required): A single ASCII error code. Example: `"invalid_request"`.
- `error_description` (string, optional): Example: `"client_id, redirect_uri and response_type are required"`.
- `error_uri` (string (uri), optional): The error code's runbook (RFC 6749 §5.2): `https://nauthera.io/runbooks/oauth/<error>`. Example: `"https://nauthera.io/runbooks/oauth/invalid_request"`.
- `state` (string, optional): Echoed authorization-request state (RFC 6749 §4.1.2.1).
- `iss` (string (uri), optional): Issuer identifier on authorization error responses (RFC 9207).

## Example request

```bash
curl -i -X POST 'https://auth.example.com/end_session'
```
