TypeScript client

Sessions and events

Read, validate, replace, and observe TypeScript client sessions.

After a successful callback, the client exposes identity and token lifetime through a Session:

interface Session {
  user?: {
    id: string;
    name?: string;
    picture?: string;
    email?: string;
    email_verified?: boolean;
  };
  access_token: string;
  expires_at?: number;
  expires_in?: number;
}

expires_at is Unix time in seconds. expires_in is recalculated as remaining seconds when the session is read.

Current limitation

Despite its name, auth.user is Session | null, not the nested user profile. Read the profile from auth.user?.user.

Initialize the client

initialize() loads state, verifier, and token from storage, then sets ready and emits the ready event. ready means initialization completed; it does not mean a user is signed in.

Browser clients begin initialization during construction. You can await completion before reading the synchronous getters:

try {
  await auth.initialize();

  const session = auth.user;
  renderAccount(session?.user ?? null);
} catch (error) {
  showInitializationError(error);
}

Unlike normal auth operations, initialize() returns Promise<void> rather than { data, error } and can reject on initialization failures.

Read a session

const { data: session, error } = await auth.getSession();

if (error) {
  showSessionError(error);
} else if (session) {
  renderAccount(session.user ?? null);
} else {
  renderSignedOut();
}

Without an in-memory session, getSession() returns data: null. If an existing token is invalid, the client clears its in-memory session, but a stale stored token can remain.

Local decoding and remote checking

CallBrowser defaultServer default
getSession()Decode onlyCheck through /userinfo
getSession({ verify: true })Check through /userinfoCheck through /userinfo
getSession({ verify: false })Decode onlyDecode only

Decode-only mode checks JWT shape, parses selected claims, and rejects an expired numeric exp. It does not authenticate the signature, issuer, audience, algorithm, key ID, nonce, or token source.

verify: true sends the bearer token to /userinfo and uses the returned profile. It does not perform local JWK verification.

Set a session

Use setSession() to import an access token from a trusted handoff or custom persistence layer. The client processes the token before storing it:

export async function importSession(accessToken: string) {
  const { data: session, error } = await auth.setSession({
    access_token: accessToken,
    verify: true,
  });

  if (error) {
    showSessionError(error);
    return;
  }

  renderAccount(session.user ?? null);
}

An empty token returns MISSING_TOKEN. Failed processing does not replace the stored token and can clear the current in-memory session.

Expiration

When a token contains a numeric exp, browser clients schedule token removal and emit a logout event at expiration. Server clients do not schedule a timer. A token without a numeric exp has no client expiration timer and may remain stored until removed.

The package has no refresh-token or silent-renewal flow. Restart sign-in when a new token is required.

Observe events

The client emits three synchronous events:

EventPayloadMeaning
readyOptional session (Session or null)Initialization completed
authA required session (Session)A session was accepted
logoutA reason: user, expired, or revokedThe local session ended

Keep the same callback reference when removing a listener. on() returns void; it does not return an unsubscribe function.

import type { Session } from "unbound-auth";

const handleAuth = ({ session }: { session: Session }) => {
  renderAccount(session.user ?? null);
};

const handleLogout = ({ reason }: {
  reason: "user" | "expired" | "revoked";
}) => {
  renderSignedOutReason(reason);
};

auth.on("auth", handleAuth);
auth.on("logout", handleLogout);

// During cleanup:
auth.off("auth", handleAuth);
auth.off("logout", handleLogout);

Listener exceptions are not isolated. Keep callbacks small and catch errors inside them if event handling can fail.

Log out locally

const { data, error } = await auth.logout();

if (error) {
  showLogoutError(error);
} else {
  renderSignedOut();
}

The successful data value is null. Logout removes only the token for an active in-memory session; it does not clear pending state/verifier, revoke the token, call an end-session endpoint, or log out from Unbound or an upstream provider. If memory has no session, logout is a no-op and may leave a stale stored token.

Review storage adapters for persistence details and client errors for invalid or expired token handling.

On this page