# Endpoints

> Every OneiD protocol endpoint with its method, path, authentication, parameters, example request and response, and errors.

Source: https://oltinid.com/docs/reference/endpoints/ · Section: Reference · All OneiD documentation: https://oltinid.com/llms.txt

OneiD exposes the standard OAuth 2.0 and OpenID Connect endpoints under your OneiD address. Paths on this page are relative to `https://YOUR_ONEID`. Read the exact URLs from the [discovery document](https://oltinid.com/docs/reference/discovery/) rather than building them by hand.

| Endpoint | Method | Path |
|---|---|---|
| [Discovery](#discovery) | GET | `/.well-known/openid-configuration` |
| [JWKS](#jwks) | GET | `/.well-known/jwks` |
| [Authorize](#authorize) | GET, POST | `/connect/authorize` |
| [Token](#token) | POST | `/connect/token` |
| [Userinfo](#userinfo) | GET, POST | `/connect/userinfo` |
| [Introspection](#introspection) | POST | `/connect/introspect` |
| [Revocation](#revocation) | POST | `/connect/revoke` |
| [End session](#end-session) | GET, POST | `/connect/logout` |

> **Not supported:** OneiD has no device authorization, pushed authorization request (PAR), dynamic client registration, session management (`check_session_iframe`), front-channel logout or back-channel logout endpoint.

## Discovery

`GET /.well-known/openid-configuration`

Returns the OpenID Connect discovery document: the issuer, every endpoint URL and the features OneiD supports. Your library reads it at startup. The [discovery document reference](https://oltinid.com/docs/reference/discovery/) explains each field.

**Authentication:** none. Any origin may call it from a browser.

**Parameters:** none.

```http
GET /.well-known/openid-configuration HTTP/1.1
Host: YOUR_ONEID
```

```json
{
  "issuer": "https://YOUR_ONEID/",
  "authorization_endpoint": "https://YOUR_ONEID/connect/authorize",
  "token_endpoint": "https://YOUR_ONEID/connect/token",
  "introspection_endpoint": "https://YOUR_ONEID/connect/introspect",
  "end_session_endpoint": "https://YOUR_ONEID/connect/logout",
  "revocation_endpoint": "https://YOUR_ONEID/connect/revoke",
  "userinfo_endpoint": "https://YOUR_ONEID/connect/userinfo",
  "jwks_uri": "https://YOUR_ONEID/.well-known/jwks",
  "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"],
  "response_types_supported": ["code"],
  "id_token_signing_alg_values_supported": ["RS256"]
}
```

The example is shortened. The full document has more fields.

> **Note:** The `issuer` ends with a slash: `https://YOUR_ONEID/`. If your library compares issuers exactly, use the value from discovery, including the slash.

**Errors:** none specific to this endpoint.

## JWKS

`GET /.well-known/jwks`

Returns the public keys that verify the signatures of ID tokens and access tokens. Each key has a `kid`. A token's header names the `kid` of the key that signed it.

**Authentication:** none. Any origin may call it from a browser.

**Parameters:** none.

```http
GET /.well-known/jwks HTTP/1.1
Host: YOUR_ONEID
```

```json
{
  "keys": [
    {
      "kid": "EXAMPLE_KID",
      "use": "sig",
      "kty": "RSA",
      "alg": "RS256",
      "e": "AQAB",
      "n": "EXAMPLE_PUBLIC_KEY_MODULUS..."
    }
  ]
}
```

During a key rotation the set contains more than one key. Cache the set and fetch it again when a token arrives with a `kid` you do not know. See [signing keys and rotation](https://oltinid.com/docs/reference/tokens/#signing-keys-and-rotation).

**Errors:** none specific to this endpoint.

## Authorize

`GET /connect/authorize` or `POST /connect/authorize`

Starts a sign-in. The browser is sent here; OneiD signs the user in (or reuses the OneiD session), asks for consent when the client requires it, and redirects back to your `redirect_uri` with an authorization code. With `POST`, send the same parameters as an `application/x-www-form-urlencoded` body.

**Authentication:** none for the client. The user authenticates in the browser.

| Parameter | Required | Description |
|---|---|---|
| `client_id` | Yes | Your client ID. |
| `response_type` | Yes | Always `code`. |
| `redirect_uri` | Yes | Must match a redirect URI registered for the client exactly. |
| `scope` | Yes | Space-separated scopes. Include `openid` for OpenID Connect. The client must be allowed every scope it asks for. |
| `code_challenge` | Yes | The PKCE code challenge: the base64url-encoded SHA-256 hash of your code verifier. |
| `code_challenge_method` | Yes | Always `S256`. |
| `state` | Recommended | An unguessable value that OneiD returns unchanged. Check it on the callback. |
| `nonce` | Recommended | An unguessable value that OneiD copies into the ID token. Check it when you validate the ID token. |
| `response_mode` | No | `query` (default) or `form_post`. |
| `prompt` | No | `none`, `login`, `select_account` or `consent`. See [Sessions, prompt and max_age](https://oltinid.com/docs/guides/sessions-and-reauthentication/). |
| `max_age` | No | Maximum time in seconds since the user last signed in. If more time has passed, the user must sign in again. |
| `id_token_hint` | No | An ID token OneiD issued earlier. If it names a different user from the one signed in, OneiD asks the user to sign in. |
| `claims` | No | A JSON object that names claims for the `id_token` and `userinfo` members. See [the claims parameter](https://oltinid.com/docs/reference/claims/#the-claims-request-parameter). |

`prompt` values:

- `none`: OneiD shows no page. If the user would have to sign in, consent or complete a pending action, OneiD returns `login_required`, `consent_required` or `interaction_required` to your redirect URI.
- `login` and `select_account`: the user must sign in again. OneiD has no account picker.
- `consent`: OneiD shows the consent page.

OneiD accepts `login_hint`, `ui_locales`, `display` and `acr_values` but they have no effect. Sending `acr_values=urn:oltin:ac:mfa` does not force MFA; check the `acr` or `amr` claim in the ID token instead.

> **Not supported:** OneiD does not accept request objects. A `request` parameter is answered with `request_not_supported` and a `request_uri` parameter with `request_uri_not_supported` at your redirect URI.

```http
GET /connect/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&scope=openid%20profile%20email&state=Xk3fQ9vLp2&nonce=n-7Hq2Lw81&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256 HTTP/1.1
Host: YOUR_ONEID
```

On success, OneiD redirects to your redirect URI with the code, your `state` and the issuer (`iss`):

```http
HTTP/1.1 302 Found
Location: https://app.example.com/callback?code=Pq7xR2...&state=Xk3fQ9vLp2&iss=https%3A%2F%2FYOUR_ONEID%2F
```

With `response_mode=form_post`, the browser posts the same values to your redirect URI as a form instead.

The authorization code is single-use and expires after 5 minutes. Exchange it at the [token endpoint](#token) straight away.

**Errors:** returned to your redirect URI as `error`, `error_description`, `state` and `iss`.

| Error | Cause |
|---|---|
| `invalid_request` | A required parameter is missing or wrong. |
| `invalid_scope` | The client is not allowed one of the requested scopes. |
| `unauthorized_client` | The client is disabled. |
| `access_denied` | The user refused consent. |
| `login_required`, `consent_required`, `interaction_required` | `prompt=none` was sent and the user would have to interact. |
| `request_not_supported`, `request_uri_not_supported` | A `request` or `request_uri` parameter was sent. |

> **Warning:** If the `client_id` is unknown or the `redirect_uri` is not registered for the client, OneiD does not redirect. It shows its own error page with `invalid_request`, because it cannot trust the redirect URI.

## Token

`POST /connect/token`

Exchanges an authorization code, a refresh token or client credentials for tokens. Send the parameters as an `application/x-www-form-urlencoded` body.

**Authentication:**

- Confidential clients authenticate with their client secret. Use HTTP Basic (`client_secret_basic`, recommended) or send `client_id` and `client_secret` in the body (`client_secret_post`).
- Public clients send `client_id` in the body and no secret.

`private_key_jwt` appears in discovery but cannot be used, because OneiD has no way to register a client's public key. Mutual TLS client authentication is not supported.

Browser applications can call this endpoint cross-origin only from an origin registered as an allowed CORS origin on the client. See [Browser applications and CORS](https://oltinid.com/docs/guides/browser-applications/).

### authorization_code

Exchanges the code from the [authorize](#authorize) redirect.

| Parameter | Required | Description |
|---|---|---|
| `grant_type` | Yes | `authorization_code`. |
| `code` | Yes | The code from the callback. |
| `redirect_uri` | Yes | The same redirect URI you sent to the authorize endpoint. |
| `code_verifier` | Yes | The PKCE code verifier whose hash you sent as `code_challenge`. |
| `client_id` | Public clients and `client_secret_post` | Your client ID. |
| `client_secret` | `client_secret_post` only | Your client secret. |

```http
POST /connect/token HTTP/1.1
Host: YOUR_ONEID
Authorization: Basic WU9VUl9DTElFTlRfSUQ6WU9VUl9DTElFTlRfU0VDUkVU
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=Pq7xR2...&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
```

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile email offline_access",
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...",
  "refresh_token": "EXAMPLE_OPAQUE_REFRESH_TOKEN"
}
```

`refresh_token` is present only when the client has the refresh_token grant and the request asked for `offline_access`. `id_token` is present when the request asked for `openid`. `expires_in` reflects the access token lifetime set for the client (1 hour by default).

### refresh_token

Exchanges a refresh token for new tokens. Every refresh returns a new refresh token; store it and discard the old one. See [Refresh tokens](https://oltinid.com/docs/guides/refresh-tokens/).

| Parameter | Required | Description |
|---|---|---|
| `grant_type` | Yes | `refresh_token`. |
| `refresh_token` | Yes | The most recent refresh token you received. |
| `client_id` | Public clients and `client_secret_post` | Your client ID. |
| `client_secret` | `client_secret_post` only | Your client secret. |

```http
POST /connect/token HTTP/1.1
Host: YOUR_ONEID
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=EXAMPLE_OPAQUE_REFRESH_TOKEN&client_id=YOUR_CLIENT_ID
```

The response has the same shape as for `authorization_code`, with a new `refresh_token`.

### client_credentials

Issues an access token to a confidential client acting for itself, with no user. Public clients cannot use this grant. No refresh token is issued; request a new access token when the current one expires. See [Client credentials for services](https://oltinid.com/docs/guides/client-credentials/).

| Parameter | Required | Description |
|---|---|---|
| `grant_type` | Yes | `client_credentials`. |
| `scope` | Recommended | Space-separated API scopes the client is allowed. The access token carries the scopes you ask for. |
| `client_id` | `client_secret_post` only | Your client ID. |
| `client_secret` | `client_secret_post` only | Your client secret. |

```http
POST /connect/token HTTP/1.1
Host: YOUR_ONEID
Authorization: Basic WU9VUl9DTElFTlRfSUQ6WU9VUl9DTElFTlRfU0VDUkVU
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=orders.read
```

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "orders.read"
}
```

In this access token, `sub` is the client ID and `name` is the client's display name.

### Token endpoint errors

Errors are returned as JSON with `error` and `error_description`.

| Error | HTTP status | Cause |
|---|---|---|
| `invalid_request` | 400 | A required parameter is missing or malformed. |
| `invalid_client` | 401 | Unknown client, wrong secret, expired secret ("The client secret has expired.") or disabled client. |
| `invalid_grant` | 400 | The code or refresh token is expired, already used or revoked; the code verifier does not match; or the user was deleted, locked, must change their password or must enrol in MFA. |
| `invalid_scope` | 400 | The client is not allowed one of the requested scopes. |
| `unsupported_grant_type` | 400 | The grant type is not one OneiD supports. |
| `slow_down` | 429 | Too many requests. See [Rate limits](https://oltinid.com/docs/reference/rate-limits/). |

## Userinfo

`GET /connect/userinfo` or `POST /connect/userinfo`

Returns claims about the signed-in user, limited to the scopes granted to the access token and any `userinfo` claims requested through the [claims parameter](https://oltinid.com/docs/reference/claims/#the-claims-request-parameter).

**Authentication:** a user access token from OneiD in the `Authorization: Bearer` header.

**Parameters:** none.

```http
GET /connect/userinfo HTTP/1.1
Host: YOUR_ONEID
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...
```

```json
{
  "sub": "3f2a9c1e-5b7d-4e1a-9c2b-7d4e8f1a2b3c",
  "name": "Alex Example",
  "given_name": "Alex",
  "family_name": "Example",
  "preferred_username": "alex",
  "idp": "local",
  "updated_at": 1700000000,
  "email": "alex@example.com",
  "email_verified": true,
  "role": ["Staff"]
}
```

`sub` is always present. Other claims appear only when their scope was granted and the user has a value. `role` is always a JSON array here. See [Claims](https://oltinid.com/docs/reference/claims/).

Browser applications can call this endpoint cross-origin only from a registered CORS origin.

**Errors:** a missing, expired or revoked access token gets HTTP 401 with a `WWW-Authenticate: Bearer` header.

## Introspection

`POST /connect/introspect`

Tells a confidential client whether a token is active, following RFC 7662. OneiD answers only for tokens issued to the calling client.

**Authentication:** confidential clients only, with their client secret (`client_secret_basic` recommended, `client_secret_post` accepted). Introspection never allows cross-origin browser requests.

| Parameter | Required | Description |
|---|---|---|
| `token` | Yes | The token to inspect. |
| `token_type_hint` | No | `access_token` or `refresh_token`. |

```http
POST /connect/introspect HTTP/1.1
Host: YOUR_ONEID
Authorization: Basic WU9VUl9DTElFTlRfSUQ6WU9VUl9DTElFTlRfU0VDUkVU
Content-Type: application/x-www-form-urlencoded

token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...&token_type_hint=access_token
```

For an active token the response contains `"active": true` and details of the token, for example:

```json
{
  "active": true,
  "iss": "https://YOUR_ONEID/",
  "sub": "3f2a9c1e-5b7d-4e1a-9c2b-7d4e8f1a2b3c",
  "client_id": "YOUR_CLIENT_ID",
  "scope": "openid profile orders.read",
  "token_type": "Bearer",
  "iat": 1700000000,
  "exp": 1700003600
}
```

For an expired, revoked or unknown token the response is:

```json
{
  "active": false
}
```

> **Tip:** Most APIs do not need introspection. Short-lived access tokens validated locally are simpler and faster. See [Protect an API](https://oltinid.com/docs/guides/protect-an-api/).

**Errors:** `invalid_client` (HTTP 401) when client authentication fails; `invalid_request` when `token` is missing.

## Revocation

`POST /connect/revoke`

Revokes a refresh token or an access token in OneiD's store, following RFC 7009. Revoke the refresh token when a user signs out of your application.

**Authentication:** confidential clients authenticate with their client secret. Public clients send `client_id` in the body. Browser applications can call this endpoint cross-origin only from a registered CORS origin.

| Parameter | Required | Description |
|---|---|---|
| `token` | Yes | The token to revoke. |
| `token_type_hint` | No | `refresh_token` or `access_token`. |
| `client_id` | Public clients and `client_secret_post` | Your client ID. |
| `client_secret` | `client_secret_post` only | Your client secret. |

```http
POST /connect/revoke HTTP/1.1
Host: YOUR_ONEID
Content-Type: application/x-www-form-urlencoded

token=EXAMPLE_OPAQUE_REFRESH_TOKEN&token_type_hint=refresh_token&client_id=YOUR_CLIENT_ID
```

A successful revocation returns HTTP 200.

> **Note:** An API that validates access tokens locally does not see a revocation until the token expires. Keep access token lifetimes short.

**Errors:** `invalid_client` (HTTP 401) when client authentication fails; `invalid_request` when `token` is missing.

## End session

`GET /connect/logout` or `POST /connect/logout`

Signs the user out of OneiD (RP-Initiated Logout 1.0) and, when you pass a registered `post_logout_redirect_uri`, sends the browser back to your application. Signing out revokes your application's tokens for the user. When users come from an upstream OpenID Connect provider, the sign-out continues to that provider. See [Sign-out](https://oltinid.com/docs/guides/logout/).

**Authentication:** none for the client. Identify your application with `id_token_hint` or `client_id`.

| Parameter | Required | Description |
|---|---|---|
| `id_token_hint` | Recommended | An ID token OneiD issued to your application for this user. |
| `client_id` | When no `id_token_hint` is sent and you use `post_logout_redirect_uri` | Your client ID. |
| `post_logout_redirect_uri` | No | Where to send the browser afterwards. Must match a post-logout redirect URI registered for the client exactly. |
| `state` | No | A value OneiD returns unchanged to `post_logout_redirect_uri`. |

```http
GET /connect/logout?id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYQU1QTEVfS0lEIn0...&post_logout_redirect_uri=https%3A%2F%2Fapp.example.com%2Fsigned-out&state=Lg5pW0 HTTP/1.1
Host: YOUR_ONEID
```

```http
HTTP/1.1 302 Found
Location: https://app.example.com/signed-out?state=Lg5pW0
```

Without `post_logout_redirect_uri`, the user ends on OneiD's signed-out page. If the `id_token_hint` names a different user from the one signed in, OneiD asks the user to confirm the sign-out first.

**Errors:** OneiD shows logout errors on its own page and does not redirect the browser.

| Error | Cause |
|---|---|
| `invalid_request` | `post_logout_redirect_uri` was sent with neither `id_token_hint` nor `client_id`. |
| `unauthorized_client` | The client is disabled. |

OneiD also refuses an `id_token_hint` it did not issue and a `post_logout_redirect_uri` that is not registered for the client.

> **Not supported:** Front-channel logout, back-channel logout and the session management iframe. Other applications the user signed in to are not notified.

## Learn more

- [Discovery document](https://oltinid.com/docs/reference/discovery/)
- [Tokens](https://oltinid.com/docs/reference/tokens/)
- [Errors and troubleshooting](https://oltinid.com/docs/reference/errors/)
