Skip to main content

Sessions & Token Handling

This page covers the VerifiedSession lifecycle — how it is created, stored, refreshed, expired, and cleared — and how to work with the access and refresh tokens it contains.


The VerifiedSession object

After a successful authenticate() call, the SDK persists a VerifiedSession to localStorage under the key mwen_verified_session. Its shape:

interface VerifiedSession {
appIdentity: string; // did:jwk — your stable user identifier
verified: true;
scopes: string[];
holder: string; // same as appIdentity
timestamp: number; // session creation time (Unix ms)
expiresAt?: number; // credential expiry (Unix ms)
access_token?: string; // signed AT+JWT (3600 s TTL by default)
refresh_token?: string; // signed RT+JWT (86400 s TTL, rotated on use)
issuerDID?: string;
claims?: Record<string, { value: unknown; format: string; zkProof?: boolean }>;
disclosedClaims?: string[];
}

appIdentity is the stable per-app did:jwk — use it as the primary key for this user in your own database.


Restoring a session on page load

On page load, call getSession() (or rely on MwenProvider to do it automatically) to restore an existing session without re-authenticating:

// Framework-agnostic
const session = client.getSession();
if (session) {
// Restore UI state from session
}
// React — handled automatically by MwenProvider
const { session } = useMwen();
// session is non-null if a valid session exists in localStorage

getSession() returns null when:

  • No session exists in localStorage.
  • The session's timestamp is older than sessionTtlMs (default: 1 hour).
  • The session's expiresAt is in the past.

Auto-refresh

The SDK schedules a proactive credential refresh at 75% of the remaining credential lifetime. For a credential with a 1-hour TTL:

  • At 45 minutes, refreshCredential() is called automatically.
  • If a delegation grant is active, this happens silently — no popup shown.
  • If no grant is active, the refresh falls back to a full authenticate() (popup shown).
  • If the refresh fails, the session is cleared. Your app should respond to session becoming null.

The timer is started after authenticate() or refreshCredential() and cancelled by signOut().


Access tokens

session.access_token is a signed AT+JWT with a 3600-second (1 hour) TTL. Send it in the Authorization header for protected API requests:

const session = client.getSession();

const response = await fetch('/api/protected', {
headers: {
Authorization: `Bearer ${session?.access_token}`,
},
});

On the server, verify it with verifyAccessTokenFromHeader(). See Verifying Credentials Server-Side.


Refresh tokens

session.refresh_token is a signed RT+JWT with an 86400-second (24 hour) TTL. It is rotated on every use — each refresh produces a new refresh token and invalidates the old one.

The SDK manages refresh tokens internally. You do not need to send or store them manually — they are read from localStorage during refreshCredential().


Cross-tab revocation

MwenProvider listens for the storage event on window. When any tab clears the mwen_verified_session key (e.g. the user signs out in another tab, or the extension fires a revocation), all other tabs update their state immediately:

// This is handled automatically inside MwenProvider.
// Your UI will re-render with session = null if another tab signs out.

If you are using MwenClient without MwenProvider, set up the listener manually:

window.addEventListener('storage', (e) => {
if (e.key === 'mwen_verified_session' && e.newValue === null) {
// Session was cleared in another tab
handleSignOut();
}
});

Explicit sign-out

// React
const { signOut } = useMwen();
<button onClick={signOut}>Sign out</button>

// Framework-agnostic
client.signOut();

signOut():

  1. Cancels the auto-refresh timer.
  2. Removes mwen_verified_session from localStorage.
  3. The storage event fires — other tabs are notified.

Session key constant

The localStorage key is exported for cases where you need to read or watch it directly:

import { VERIFIED_SESSION_KEY } from '@mwen/js-sdk';
// 'mwen_verified_session'