Refresh tokens and sessions
Keep users signed in with SenseCrypt refresh tokens — requesting offline_access, handling rotation and reuse detection, revoking sessions, and implementing logout without a server-side SSO cookie.
SenseCrypt has no server-side SSO cookie — every sign-in is a fresh, on-device face ceremony. "Keeping a user signed in" and "logging them out" are therefore about tokens, not a session cookie on the IdP. This guide covers refresh tokens, rotation, revocation, and logout.
Request a refresh token
A refresh token is issued only when you request the offline_access scope at the authorization step:
GET /v1/idp/oidc/authorize?client_id=...&scope=openid%20offline_access%20profile&...If you omit offline_access, no refresh token comes back — the access token stands alone until it expires. Refresh tokens are opaque (not JWTs); treat them as bearer secrets and store them securely.
Refresh an access token
Exchange the refresh token at the token endpoint:
POST /v1/idp/oidc/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=<token>&client_id=<id>(Confidential clients also present their client credential per their registered auth method.) You get a new access token — and, when rotation is enabled, a new refresh token you must store in place of the old one.
Rotation and reuse detection
Depending on the app's configuration — and always for SPA (public) clients — each refresh rotates the token and returns a successor. This is a security feature, but it has rules you must respect:
- Always store the newest refresh token returned and discard the previous one.
- Reusing an already-rotated token outside a short overlap window is treated as a breach: SenseCrypt revokes the entire token family and returns
invalid_grant. A stolen-and-replayed token thus takes out the legitimate session too — the safe failure. - Avoid racing refreshes. Two concurrent requests using the same refresh token can trip reuse detection. Serialize refreshes in your client, or rely on the short overlap window.
The access gate re-runs on every refresh
A refresh is not a free pass — it re-runs the full access gate and recomputes permissions:
- A user who has been suspended, deleted, un-enrolled, or removed from the app's groups fails closed on their next refresh.
- The
permissionsclaim is recomputed fresh on every refresh, so a revoked role or a removed group membership shrinks the next access token — you don't wait for expiry.
Absolute lifetime
Every token family has an absolute lifetime fixed at issuance that rotation can never extend. When it lapses, the user must sign in again (a fresh face ceremony). Plan your UX around a periodic re-authentication rather than indefinite sessions.
Revoke a session (RFC 7009)
To end a session server-side, revoke a token at the revocation endpoint:
POST /v1/idp/oidc/revoke
Content-Type: application/x-www-form-urlencoded
token=<refresh_or_access_token>&client_id=<id>- Revoking a token revokes the refresh-token family it belongs to.
- If the presented token parses as one of the client's access tokens, its
jtiis denylisted until it expires. - The endpoint always returns an empty
200, whether or not the token was found — there is no validity oracle. (Client authentication still applies: a bad client credential returnsinvalid_client.)
Log out (RP-Initiated Logout)
Because there's no OP-side SSO cookie, "logout" means revoking the subject's tokens. Use the logout endpoint:
GET /v1/idp/oidc/logout?id_token_hint=<id_token>&post_logout_redirect_uri=<url>&state=<opaque>Key requirements:
id_token_hintis required. It's the only way the IdP knows which subject to act on — a missing hint isinvalid_request(not a silent success that falsely claims the user signed out). The hint is verified for signature and issuer, but an expired hint is accepted.- Logout revokes every live refresh token for that
(subject, client). - Any
post_logout_redirect_urimust be on the client's dedicated post-logout allow-list — which is separate from the/authorizecallback allow-list. Otherwise it's rejected (never an open redirect).stateis round-tripped onto the redirect. - With no redirect URI, a static "You have been signed out" page is returned.
A note on access-token validity
Access tokens are self-contained JWTs — they remain valid until exp unless explicitly revoked (their jti denylisted, or their family revoked). Two implications:
- Keep access-token lifetimes short and refresh as needed, so that suspensions and permission changes take effect promptly.
- Your resource servers get immediate revocation only if they check the denylist (via the introspection endpoint) or if the access token expires soon. Local JWT verification alone will honor a token until
exp.
Eager revocation on lifecycle events
You rarely need to revoke tokens by hand for lifecycle changes — SenseCrypt does it eagerly:
- SCIM
active: false/ delete, account self-delete, and group-member removal all immediately revoke the affected user's device keys and refresh-token families. - Outstanding access tokens then read as inactive through introspection.
So removing a user from a group, or suspending them, ends their ability to refresh right away — you don't have to call the revocation endpoint yourself.
Related
- Tokens & sessions — token contents and signing.
- Groups and access — the gate that re-runs on refresh.
- Security best practices — where and how to store tokens.
- Error codes —
invalid_grantand revocation behavior.
Customize the sign-in experience
Brand the SenseCrypt sign-in page per OIDC application — organization name, primary and accent colors, and a logo you upload — so users see your identity, not a generic prompt.
Account lifecycle and deletion
How a SenseCrypt account is closed and reopened — owner-only self-delete with a 30-day grace, the 423 block on the admin console during that window, what reactivation restores, and the crypto-shred and data erasure that happen on final deletion.