Skip to content
TDACorpIDENTITYSign in

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 https address 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_code and, if you use offline access, refresh_token. A service holds client_credentials and token_exchange, and its targets hold token_exchange too.
  • 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, nonce and 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 iss and state on 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.
  • returnTo can only be a path on your own site. Anything else is an open redirect.
  • A person who says no is handled. access_denied leads 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 scope from 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_grant on 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's sub. An access token carries the person's real sub, so never compare the two. See Get a client registered.
  • You store the ID token's sid with 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 publicOrigin is 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 its insufficient_user_authentication challenge with rp.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_nonce is 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.

Verified against commit ca46b57