Going-live checklist
What to confirm about your registration, keys, flows, sessions and behaviour under failure before real people sign in.
On this page
Work through this list once before you send real traffic through identity, and again when something about your registration or deployment changes. Each item says why it matters and where to read more. An item you cannot tick is a decision to make on purpose, not one to find out about later.
Registration#
- The client is registered for the production address. The redirect address is the exact
httpsaddress production uses, in canonical form: lower-case host, no default port, explicit path. A development address registered with it is a mistake to remove. See Get a client registered. - Only the scopes you use are registered. A smaller list means a shorter consent screen and less to lose. See Scopes and consent.
- The grants match what you built. A web application holds
authorization_codeand, if you use offline access,refresh_token. A service holdsclient_credentialsandtoken_exchange, and its targets holdtoken_exchangetoo. - The post-logout redirect addresses and the back-channel logout address are registered, if you use them. See RP-initiated logout and Back-channel logout.
- Your product is installed in every organization your people sign in to. A client enters an organization only if it is first-party, is that organization's own, or its product is installed there; otherwise sign-in answers
access_denied. See Get a client registered. - The client name is what people know your product by. It is the only detail about your client the consent screen shows today. See Consent screens.
Keys and secrets#
- The client private key and the DPoP key are in a secret store, not in the repository, a container image, or a log.
- The DPoP key outlives a restart. It is generated once and loaded at start-up. A key that is made fresh each time loses every refresh token at the next deploy. See DPoP.
- You know how to rotate the client key. Send a new public key and
kid, deploy with it, then have the old one revoked. See Client authentication. - No secret ever reaches a browser. The browser sees redirects and your own session cookie, never a token, a key or an assertion.
Environment#
- The issuer is configured, and compared byte for byte. One string,
https, no trailing slash. Endpoints come from discovery and are cached. See Environments and the issuer. - Your servers' clocks are synchronized, and you alert if they stop being. See Clock skew.
- The SDK version is pinned in your lockfile, and you know how you will take the next one: read its changelog first, because a major version can break the public API.
The sign-in flow#
state,nonceand the PKCE verifier are generated fresh for every sign-in and kept on the server, tied to the one browser that started it.- You check
issandstateon the redirect back, before anything else. See Authorization code with PKCE. - You verify the ID token fully: signature,
iss,aud,exp,nonce. If it fails, you discard the tokens and revoke the refresh token. returnTocan only be a path on your own site. Anything else is an open redirect.- A person who says no is handled.
access_deniedleads to a page that explains what they can do. See Consent screens. - An optional scope that was not granted does not break your application. You read
scopefrom the token response, not from what you asked for.
Tokens and sessions#
- Refresh tokens are stored on the server, with the DPoP key they are bound to, and refreshes are serialized per token. The new token is saved before the old one is dropped. See Refresh tokens.
invalid_granton refresh signs the person out of your application and starts a new sign-in. It does not retry. It is also what a refresh answers once your product's installation in the organization is suspended.- Access tokens are cached until shortly before they expire and never logged.
- If your client is registered
pairwise, you key accounts on the ID token'ssub. An access token carries the person's realsub, so never compare the two. See Get a client registered. - You store the ID token's
sidwith your session, so that back-channel logout can end it. - Your logout clears your own session, then asks identity to end its session, with the ID token as a hint. See RP-initiated logout.
- Your back-channel logout handler is idempotent, answers with a success only after your session is ended, and stores replay state in something shared by all instances.
Your API, if you have one#
- The audience is right for the token you expect: your resource address for a person's token, your client id for an exchanged one. See Protect your API.
- The
publicOriginis the address your callers use, not an internal one behind a proxy. - The DPoP replay store is shared if you run more than one instance, and a rate limit sits in front of the API. See Protect an API in Node and Express.
- Routes that need a scope check it. The verifier does not.
- A route that needs a recent or strong sign-in sets
requireAuthentication, and your client answers itsinsufficient_user_authenticationchallenge withrp.stepUpUrl. See Protect your API. - Something decides what the caller may do. A verified token proves who is calling, not what they may do. Use identity's decision client, or your own rules. See Decision client.
When things fail#
- A 429 is obeyed, with the wait, jitter and a cap, and only safe requests are repeated. See Rate limits and retries.
use_dpop_nonceis retried once, with a new proof and a new assertion.- Your people see a plain message, not an error code, and your logs have the code, the endpoint, the client id and a correlation id. See Error handling.
- No log line contains a token, a code, an assertion, a proof or a key.
- You have tried the failure paths. Deny consent, let a code expire, revoke the app from the account's connected apps, sign out in another tab, and stop the clock sync on a test machine. Each should end in a clear state.
Last, ask#
Tell TDACorp you are about to go live: the client id, the expected load and the date. Nothing about a live deployment can be assumed from this page, and a short note beforehand costs less than a surprise afterwards.