Identity

Sessions and tokens

What a sign-in issues, how long it lasts, how your backend learns who is calling, and why a token is refused.

A sign-in issues a session: a short-lived access token that your frontend sends with every request, and a refresh token that renews it. Your backend never calls ShipRev to check a request; it verifies the access token locally with the Server SDK and reads the caller's account, organization and application from it.

What a sign-in returns

Whenever the region issues a session, on sign-in, on sign-up, after a social sign-in or once an end user confirms their email address, it answers with the same fields:

FieldWhat it is
access_tokenA signed token for one account, in one buyer organization, for one application. Send it as Authorization: Bearer <access_token>
expires_inSeconds until the access token expires: 900, that is 15 minutes
refresh_tokenRenews the session. Send it only to POST /public/v1/auth/refresh and POST /public/v1/auth/logout, never to your own API routes
accountThe end user's profile, their memberships and the current organization

The hosted pages keep the session on your brand domain. On your own pages, SignInForm and SignUpForm hand it to you, and you store it; see Hosted pages, components or your own.

How long a session lasts

EventEffect
Access token expires after 15 minutesRenew it with POST /public/v1/auth/refresh and the refresh token. Each renewal also returns a new refresh token, and the old one stops working
No renewal for 30 daysThe session ends; the end user signs in again
The end user signs out (POST /public/v1/auth/logout with the refresh token)That session can no longer be renewed. Their other sessions continue
The end user changes their passwordEvery other session of theirs ends; the one they changed it from continues
The end user resets their passwordEvery session of theirs ends

Ending a session stops renewals, not access tokens already issued. Your backend verifies access tokens on its own, so one that was issued before the session ended keeps verifying until it expires, at most 15 minutes later. Keep that window in mind for anything you would revoke at once.

How your backend knows who is calling

Verify the access token with verifyToken() and use what it returns:

handler.ts
const claims = await shiprev.verifyToken(token);
// claims.account_id       the end user's account
// claims.organization_id  the buyer organization the session is in
// claims.project_id       your application

Rule on entitlements and report usage with claims.organization_id, and tie your own records to account_id and organization_id. Never take an organization from a header, a parameter or the request body, because the caller controls those. Protect routes: token, then capability shows the full route in NestJS and without it, and the Server SDK reference lists every claim.

Verification needs no configuration and keeps working while the region is unreachable. It checks the signature against your region's keys, the expiry, and that the token is an end-user session token of your application. It needs the client to have reached the region once after it started.

Why a token is refused

Treat every failure of verifyToken() as a 401. A malformed, badly signed or expired token throws a plain Error. A token that is correctly signed and unexpired but not a session token of your application throws TokenRejectedError, and its reason says why:

reasonWhat it usually means
not_readyYour service has just started and the client has not reached the region yet; every token is refused until it has
audience_mismatchThe token is not an end-user session token, for example an operator console token
issuer_mismatchThe token was issued by another region or another sign-in gate
project_mismatchThe token was issued for another of your applications
not_a_session_tokenThe token is a one-time token, such as one from a password reset link
missing_expiryThe token carries no expiry

An expired access token is the common case: the frontend renews it and retries. With the React components, onUnauthorized is where that happens; see getAccessToken and onUnauthorized.

Switching organizations

A session is in one buyer organization at a time. An end user who belongs to several switches with POST /public/v1/auth/switch, naming the organization; the answer is a new access token for it, without a refresh token. An organization the end user does not belong to is refused.

The switch is remembered for the next sign-in, which starts in the organization the end user used last. A renewal is different: POST /public/v1/auth/refresh returns a token for the organization the session was opened in, as long as the end user still belongs to it. If your application lets end users switch, switch again after each renewal. Buyer organizations covers the rest.

© 2026 ShipRev