Tokens

The access, refresh and ID tokens: what each is for, how long it lives, how they are renewed and revoked, and what is safe to log.

A sign-in produces up to three tokens. They look similar and do different jobs.

TokenFormForServer default lifetime
Access tokenOpaque stringCalling the UNET API as the person, and asking for their profile1 hour
Refresh tokenOpaque stringGetting a new access token without asking the person again60 days, renewed on each use
ID tokenSigned JWTTelling your server who signed in and that it was for your app1 hour

The access token

It is opaque: a random string with no readable content. Only UNET can say what it means, which is the point. It cannot be decoded, forged or tampered with, and revoking it works at once, because UNET looks it up on every use instead of trusting a signature.

Use it only through the SDK (unet.api.*), or send it to UNET. Do not send it to your own server to "log the person in": your server cannot tell whom it belongs to, or which app it was issued to, without asking UNET. Send the ID token instead, or verify the access token with your App Secret. See Verify on your server.

The refresh token

It is issued when your app asks for offline_access (the console's "Stay signed in"). The SDK adds prompt=consent for you in that case, as OpenID Connect requires for a refresh token to be issued.

  • It rotates. Every refresh returns a new refresh token and ends the old one, and each new one gets a fresh lifetime. That lifetime is how long a person may stay away without signing in again.
  • A short reuse window exists. If the response to a refresh is lost (a dropped connection, a closed tab) the old token is accepted once more for about a minute, so a harmless retry does not sign the person out. Reusing an old token after that ends the whole session, because it looks like theft.
  • The grant caps it. The person's permission for your app (the grant) lasts 180 days by default. When it expires, the refresh token ends with it.
  • Several tabs. With storage: "local" the SDK serialises refreshes across tabs (Web Locks), so a rotating token is never spent twice.

A refresh that fails with invalid_grant means the permission is gone, and the SDK ends the session (SessionExpired). Any other failure, such as no network or a server error, keeps the tokens, and the next call tries again.

Without offline_access there is no refresh token. When the access token expires, the session ends and the person signs in again.

The ID token

It is a signed JWT (RS256) made for your App ID. It says who signed in (sub), who issued it (iss), who it was for (aud) and when it expires. It does not carry the profile: the profile comes from the userinfo endpoint.

It is for your server. A single-page site that has a backend of its own can send await unet.getIdToken() with a request, and the server checks it with verifyIdToken. The check is local and needs no request to UNET once the signing keys are cached. It proves who signed in and that it was meant for your app, not that the person still allows your app. For that, use a website app and verifyAccessToken. See Verify on your server.

Revocation

A session ends, and its tokens stop working, when:

  • the person removes your app in their settings, under connected apps. This takes effect immediately;
  • your app calls unet.signOut(), which revokes the refresh token (or the access token, if there is no refresh token) and clears the session;
  • the person signs out of UNET everywhere, or changes their password, or recovers their account;
  • your app is turned off or deleted in the console;
  • the account is deleted.

After a revocation, the access and refresh tokens stop working at once, the next refresh fails, and the SDK reports SessionExpired. The one exception is the ID token: it is a signed statement that stays valid until it expires (an hour), which is why it proves who signed in but not that the person still allows your app.

A website app can also register a back-channel logout address, so UNET tells your server when a person leaves. See the console docs.

What is safe to log

ValueSafe to log?
sub, username, displayNameYes
The App IDYes
Access, refresh and ID tokensNo. Anyone who has one can act as the person until it ends.
The authorization code and the PKCE verifierNo.
Your App SecretNo. Never in browser code at all.

The SDK's onTrace hook shortens tokens, codes and verifiers to their first characters plus their length before it hands you a trace, so a trace is safe to paste into a bug report. Your own logging has no such protection: do not log request headers or token responses.