Security best practices
Check your OneiD integration against a list of practices for flows, secrets, tokens, sessions and APIs before you go live.
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
S256in every application, including server-side applications. Public clients must use PKCE; confidential clients have it required by default. Keep it on. - Send
stateand 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
nonceand check it in the ID token. It stops a stolen ID token from being replayed into your application. - Check
issin the authorisation response. OneiD includesissin 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_clientwith “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_postalso works.
Tokens in your application
- Validate ID tokens before you trust them: signature (RS256),
isswith the trailing slash,audequals your client ID,exp, andnonce. See 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.
- Treat
invalid_granton 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
suband the token’s expiry instead if you need a trace. - Request the fewest scopes you need. Ask for
offline_accessonly 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=nonechecks and failed refreshes are how you notice. See Sessions, prompt and max_age. - Sign out properly. Clear your session, then send the user to OneiD’s end-session endpoint with
id_token_hint. See Sign-out. - Check
amroracrbefore sensitive actions. OneiD does not enforceacr_values; asking forurn:oltin:ac:mfadoes not force MFA. If an action needs MFA, check thatacrisurn:oltin:ac:mfaorurn:oltin:ac:externalas your policy allows, or thatamrcontainsmfa. 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_ageorprompt=loginand then checkauth_timein the new ID token.
APIs
- Validate every access token: RS256 signature,
isswith the trailing slash,exp, and the required scope. Do not requireaud; 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.
- 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
expandnbf.
Behaving well
- Handle HTTP 429. When OneiD answers 429, wait for the number of seconds in the
Retry-Afterheader before you try again. Do not retry in a tight loop. See 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 (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.