auth.isdocs
Features

Token lifetimes & refresh

A login yields short-lived ID and access tokens and, when you ask for it, a long-lived refresh token to mint fresh ones without sending the user back through the login page. The defaults are sensible; you can tune them per client within bounds.

Defaults

TokenDefault lifetimeWhat it is
ID token1 hourThe signed identity token — your app's proof of who logged in.
Access token1 hourBearer token for userinfo; for an API resource, a per-resource JWT with its own TTL.
Refresh token14 daysOpaque token to obtain new access/ID tokens without re-login.
Authorization code10 minutesSingle-use, exchanged at the token endpoint.

The ID and access tokens are deliberately short — an hour bounds the blast radius of a leaked token, and a refresh token (or a fresh login) replaces them silently.

Getting a refresh token

A refresh token is gated, not automatic. You get one only when all of these hold:

  1. The client is allowed the refresh_token grant.
  2. The authorization request includes the offline_access scope.
  3. The request also carries prompt=consent.

Drop any one and no refresh token is issued. This is the same gate described in Scopes & claims; the curl guide shows the exact request parameters.

Tuning per client

An owner can override a client's ID-token and refresh-token lifetimes with update_client_token_ttls, within bounds that mirror the IDP's own clamp exactly:

OverrideMinMax
id_token_ttl60 s14,400 s (4 h)
refresh_token_ttl60 s4,838,400 s (56 days)

The ceilings are 4× the defaults — a misconfigured value can never mint a year-long token. The bounds are enforced at the management API, so a value outside the range is rejected (400), not silently clamped: what you set is what the IDP honors.

Using and revoking a refresh token

Exchange a refresh token at the token endpoint (grant_type=refresh_token) to get a new access token and ID token. auth.is rotates the refresh token on every use: each exchange returns a new refresh_token value and retires the one you sent. Always store the value from the latest response and send that one next time — the previous value is now spent.

This gives you automatic reuse detection. A refresh token is single-use, so if a spent value is ever presented again — the tell-tale sign that a token was stolen and replayed — auth.is does not just reject that one request: it revokes the entire grant family (every access and refresh token issued from that authorization). The legitimate client, whose newest token was also part of that family, is signed out and must re-authenticate. A leaked refresh token is therefore useful to an attacker for at most one exchange before the whole line is burned down. (This is stricter than phase 1, which left refresh tokens reusable until expiry.)

There is no grace window: two requests racing on the same refresh value will trip reuse detection, so a client must persist each rotated value before issuing the next refresh rather than refreshing the same token concurrently.

Revocation is also immediate and server-side. Post a token to the revocation endpoint (RFC 7009) — for example on logout of a single device — and it stops working at once:

POST https://{slug}.auth.is/oidc/token/revocation   token=<refresh_or_access_token>&token_type_hint=refresh_token

A password reset revokes the account's refresh tokens wholesale as part of sweeping its sessions and grants — see Sessions & SSO. The curl guide §7–8 walks refresh and revocation with real commands.

API access tokens

An access token minted for an API resource is a JWT signed with the issuer's keys, and it uses that resource's configured access-token TTL (default 1 hour), independent of the client's id/refresh overrides. A plain userinfo access token (no resource indicator) is opaque and uses the 1-hour default.

Exchanged tokens (first-party service exchange)

When you call the management API through the MCP server, the MCP does not forward your token — it trades it at the token endpoint (RFC 8693 token exchange) for a fresh access token audience-bound to the API it is about to call. Each auth.is API accepts only its own audience; the exchange is what bridges them. Exchanged tokens have their own lifetime rules:

  • TTL = min(the target resource's access-token TTL, the subject token's remaining lifetime). A derived credential never outlives the token it derives from — exchange a token with ten minutes left and the result lives at most ten minutes.
  • No refresh token, ever. When an exchanged token expires, the service simply re-exchanges — which requires the original (subject) token to still be valid. Kill the source and the derivation chain dies with it at the next exchange.
  • No per-token revocation once issued. Like every per-resource access token here, an exchanged token is a stateless JWT verified offline against the issuer's keys, so there is no server-side record to revoke. The exposure is bounded by the TTL cap above plus strict scope attenuation (the exchanged scope is always a subset of the subject's — never widened): an exchanged token is never more powerful, nor longer-lived, than presenting the subject token directly.
  • Impersonation, not delegation (RFC 8693 §1.1). The exchanged token keeps the subject's identity unchanged and carries no act/may_act claims — the API sees you, with the exchanging service invisible in the token.

Exchange is a first-party mechanism between auth.is services (only confidential, first-party service clients may call the grant, and only along seeded pairings). Customer and DCR-registered clients cannot use it.

Device sign-in (no browser on the device)

For an input-constrained or headless device — a CLI, a TV app, an agent that cannot open a browser — auth.is supports the Device Authorization Grant (RFC 8628). Add urn:ietf:params:oauth:grant-type:device_code to the client's grant_types, then:

  1. The device POSTs to the device authorization endpoint (/device/auth) and gets back a user_code, a verification_uri, and a device_code.
  2. It shows the user the short user_code and asks them to open the verification_uri (published as device_authorization_endpoint / code_verification in discovery) in any browser — on their phone, say. They enter the code, confirm, and sign in through the normal login → consent chain. The device itself never handles the user's credentials.
  3. Meanwhile the device polls the token endpoint (grant_type=urn:ietf:params:oauth:grant-type:device_code + the device_code), honoring the interval and backing off on slow_down. Once the human approves, the poll returns the same ID / access / refresh tokens a browser login would — with the same lifetimes and the same offline_access gate for a refresh token.

The device_code is valid for 10 minutes — the window the user has to approve — after which polling returns expired_token and the device must start over. Because the user_code is short and human-typeable, the verification page is per-IP rate-limited against guessing.

Personal access tokens (headless CI)

When there is no human at all — a CI job, a cron task, a build agent — the device grant's single browser approval is still one approval too many. For that case auth.is issues Personal Access Tokens (PATs): long-lived, team-scoped, revocable credentials you mint once and hand to the machine.

A PAT is bound to exactly one team and carries the mgmt management scope — the same subset the management API accepts from an interactive login, confined to that one team. It can never carry admin (the operator surface is unreachable from a PAT), and it can never mint or revoke PATs (no self-propagation — those two operations require a real interactive login).

Mint one through the management API (mint_pat) or the dashboard. The response contains the plaintext token exactly once:

authis_pat_Xm9dQ2...           # shown once — store it now, it cannot be retrieved again

Only a SHA-256 hash of the token is stored server-side, alongside a 4-character last4 tail so you can recognise it in a list. Send it as a normal bearer token to the management API:

Authorization: Bearer authis_pat_<value>
PropertyValue
Prefixauthis_pat_ (32 bytes of entropy, base64url)
Scopemgmt, confined to the bound team — never admin
Expiry90 days by default; you may set any expiry up to 1 year
At restSHA-256 hash only (never the raw value); last4 for display
RevocationImmediate — the token’s creator or a team owner may revoke it

A PAT is fixed-TTL: there is no refresh. When it nears expiry, mint a new one and revoke the old. Treat the value like a password — anyone holding it can act as you within that one team until it expires or is revoked, so store it in your CI secret manager, never in source. Failed PAT lookups are per-IP rate-limited, so a leaked-and-rotated token can't be brute-forced by prefix. Revoke immediately on any suspicion of leak; revocation takes effect on the next request.

Next steps