# Security best practices

> Check your OneiD integration against a list of practices for flows, secrets, tokens, sessions and APIs before you go live.

Source: https://oltinid.com/docs/guides/security-best-practices/ · Section: Guides · All OneiD documentation: https://oltinid.com/llms.txt

Use this page as a checklist before an application or API goes live with OneiD. Each item says what to do and why. Most OpenID Connect libraries do the protocol checks for you when you configure them correctly.

## Sign-in requests

- [ ] **Use the authorization code flow with PKCE and `S256` in every application**, including server-side applications. Public clients must use PKCE; confidential clients have it required by default. Keep it on.
- [ ] **Send `state` and check it on the callback.** It binds the response to the browser that started the sign-in and stops cross-site request forgery. Use a fresh, unguessable value for each request.
- [ ] **Send `nonce` and check it in the ID token.** It stops a stolen ID token from being replayed into your application.
- [ ] **Check `iss` in the authorisation response.** OneiD includes `iss` in every authorisation response (RFC 9207). It must equal the issuer from discovery.
- [ ] **Register exact redirect URIs.** OneiD compares redirect URIs exactly and allows no wildcards. Register one URI per environment instead of a pattern.
- [ ] **Use https everywhere.** OneiD accepts http redirect URIs only for loopback addresses (`localhost`, `127.0.0.1`, `[::1]`), for local development and desktop applications.
- [ ] **Do not reload the callback page.** An authorisation code works once. A second attempt fails with `invalid_grant`.

## Client secrets

- [ ] **Never put a client secret in a browser, mobile or desktop application.** Anything shipped to a user's device can be read. These applications are public clients and use PKCE without a secret.
- [ ] **Keep the secret in a secret store**, such as your platform's secret manager or environment variables injected at run time. Do not commit it to source control or put it in a configuration file in a repository.
- [ ] **Plan secret rotation.** A client has one secret at a time. When an administrator replaces it, the old secret stops working immediately. Agree a moment with your OneiD administrator, update your application at the same time, and check that sign-in works afterwards.
- [ ] **Know when the secret expires.** An expired secret gives `invalid_client` with "The client secret has expired." Ask your administrator for the expiry date and put the replacement in your calendar.
- [ ] **Send the secret with `client_secret_basic`** (HTTP Basic authentication). `client_secret_post` also works.

## Tokens in your application

- [ ] **Validate ID tokens** before you trust them: signature (RS256), `iss` with the trailing slash, `aud` equals your client ID, `exp`, and `nonce`. See [Tokens](https://oltinid.com/docs/reference/tokens/).
- [ ] **Store tokens where only your application can read them.**
  - Server-side web applications: in the server-side session, not in a cookie the browser can read.
  - Browser applications: in memory. Avoid `localStorage`, which any script on the page can read.
  - Mobile and desktop applications: in the operating system's secure storage.
- [ ] **Handle refresh-token rotation.** Every refresh returns a new refresh token. Store the new one and discard the old one. Do not run two refreshes with the same token at the same time: a refresh token used again after a short grace period is refused, and OneiD then revokes the whole chain, including newer tokens. See [Refresh tokens](https://oltinid.com/docs/guides/refresh-tokens/).
- [ ] **Treat `invalid_grant` on refresh as "sign in again".** It also happens when the user was locked, deleted or must change the password.
- [ ] **Never log tokens, codes or secrets.** Do not put them in URLs you build yourself, error messages or analytics. Log the `sub` and the token's expiry instead if you need a trace.
- [ ] **Request the fewest scopes you need.** Ask for `offline_access` only when the application really needs to work without the user present.

## Sessions and sensitive actions

- [ ] **Keep application sessions short.** OneiD does not notify other applications when a user signs out of one application. Each application keeps its own session until it ends. Short sessions, `prompt=none` checks and failed refreshes are how you notice. See [Sessions, prompt and max_age](https://oltinid.com/docs/guides/sessions-and-reauthentication/).
- [ ] **Sign out properly.** Clear your session, then send the user to OneiD's end-session endpoint with `id_token_hint`. See [Sign-out](https://oltinid.com/docs/guides/logout/).
- [ ] **Check `amr` or `acr` before sensitive actions.** OneiD does not enforce `acr_values`; asking for `urn:oltin:ac:mfa` does not force MFA. If an action needs MFA, check that `acr` is `urn:oltin:ac:mfa` or `urn:oltin:ac:external` as your policy allows, or that `amr` contains `mfa`. If MFA must always happen, ask your administrator to make MFA mandatory for the users.
- [ ] **Ask for a fresh sign-in when it matters.** Use `max_age` or `prompt=login` and then check `auth_time` in the new ID token.

## APIs

- [ ] **Validate every access token**: RS256 signature, `iss` with the trailing slash, `exp`, and the required scope. Do not require `aud`; OneiD access tokens have none.
- [ ] **Use distinct scopes per API**, so a token for one API cannot be used at another. See [Protect an API](https://oltinid.com/docs/guides/protect-an-api/#use-one-scope-per-api).
- [ ] **Cache the JWKS** and re-fetch it when a token has an unknown `kid`. Do not fetch it on every request.
- [ ] **Allow a small clock skew**, no more than a minute or so, when you check `exp` and `nbf`.

## Behaving well

- [ ] **Handle HTTP 429.** When OneiD answers 429, wait for the number of seconds in the `Retry-After` header before you try again. Do not retry in a tight loop. See [Rate limits](https://oltinid.com/docs/reference/rate-limits/).
- [ ] **Cache client credentials tokens** until shortly before they expire, instead of requesting a new token per call.
- [ ] **Read the discovery document** instead of hard-coding endpoint addresses.

## Reporting a security problem

If you find a security problem in OneiD, report it privately through the [contact page](https://oltinid.com/contact/?topic=security) (topic: Security report). The contact details are also published at `https://oltinid.com/.well-known/security.txt`. Please do not share details publicly before we have had a chance to respond.

## Learn more

- [Authorization code flow with PKCE](https://oltinid.com/docs/guides/authorization-code-pkce/)
- [Refresh tokens](https://oltinid.com/docs/guides/refresh-tokens/)
- [Protect an API (validate access tokens)](https://oltinid.com/docs/guides/protect-an-api/)
- [Errors and troubleshooting](https://oltinid.com/docs/reference/errors/)
