Sessions
A session is OrthID’s record of a signed-in actor: who they are, which organisation is active, on which device, and for how long.
When an actor signs in, OrthID creates a session and binds it to the device that authenticated. The session is the source of truth for the current actor, the active organisation, and the granted scope. Your app reads it through hooks on the client (useSession) and verifies it on the server before trusting any request.
Lifecycle
A session moves through three stages:
- Sign-in - the actor authenticates and OrthID issues a session plus a short-lived access token and a longer-lived refresh token. See Tokens.
- Refresh - when the access token nears expiry, the SDK silently exchanges the refresh token for a fresh access token. The session stays alive without the actor signing in again.
- Revoke - the actor signs out, an admin ends the session, or a policy expires it. The refresh token is invalidated immediately and the session can no longer be refreshed.
Active devices
A single actor can hold several sessions at once - laptop, phone, a second browser. OrthID tracks each as an active device with its own session id, so an actor (or an admin) can review where they are signed in and revoke any one of them without touching the others. The <UserButton/> surfaces this list to end users.
Verify a session server-side
Never trust a token from the client without verifying it. On the server, pass the access token to orthid.sessions.verify. It checks the signature, expiry and region, then returns the session together with the resolved actor. If the token is invalid, expired or revoked, it throws.
import { orthid } from "@orthid/sdk";
export async function GET(req: Request) {
const token = req.headers.get("authorization")?.replace("Bearer ", "");
try {
const { session, actor } = await orthid.sessions.verify(token);
// actor.type is "user" | "organization" | "agent"
if (!session.scope.includes("records:read")) {
return new Response("Forbidden", { status: 403 });
}
return Response.json({ ok: true, actor: actor.id });
} catch {
return new Response("Unauthorized", { status: 401 });
}
}Session claims
A verified session carries the claims your authorisation logic needs. The most important ones:
id- the session identifier, unique per device.actor- the resolved principal and its type.organization- the active organisation, if any.scope- the permissions granted to this session.expiresAt/issuedAt- the access token window.region- where the session and its data live.
{
"id": "sess_5hN2qB",
"actor": { "type": "user", "id": "user_3kP9aZ" },
"organization": "org_2bT7uX",
"scope": ["records:read", "summaries:write"],
"device": { "id": "dev_8cR1", "name": "MacBook Pro", "lastSeen": "2026-06-22T12:31:00Z" },
"issuedAt": "2026-06-22T12:30:00Z",
"expiresAt": "2026-06-22T12:40:00Z",
"region": "au-syd-1"
}Next steps
- Tokens & token exchange - what is inside the access and refresh tokens.
- RBAC & permissions - how
scopeis decided.