Understanding token expiration, validation, and automatic renewal in @woographql/session-utils.
This guide explains how tokens are managed throughout their lifecycle, including initialization, validation, renewal, and cleanup.
Each token type has a different default expiration:
| Token | Default Expiration | Renewal Mechanism |
|---|---|---|
| Session Token | 14 days | startSession callback |
| Auth Token | 15 minutes | refreshAuthToken callback |
| Refresh Token | ~365 days | Login mutation |
| Client Session ID | 1 hour | Automatic renewal |
When initializeSession() is called:
┌─────────────────────────────────────────────────────────────┐
│ initializeSession() │
├─────────────────────────────────────────────────────────────┤
│ 1. Check if refresh token exists and is valid │
│ - If invalid, clear all tokens │
│ - If authOnly behavior and invalid, throw error │
│ │
│ 2. If auth enabled and refresh token valid: │
│ - Check if auth token is valid │
│ - If invalid, call refreshAuthToken() │
│ │
│ 3. If session token invalid: │
│ - Call startSession() to get new session token │
│ │
│ 4. If withClientSession behavior: │
│ - Generate client session ID │
│ - Call updateSession() to save it server-side │
│ - Start client session ID renewal timer │
│ │
│ 5. Mark session as initialized if hasTokens() returns true │
└─────────────────────────────────────────────────────────────┘
Tokens are validated using JWT decoding. The isTokenValid() function checks:
exp claim)// Example validation flow if (!isTokenValid(sessionToken)) { // Token is expired or malformed await tokenManager.renewTokens(); }
When configured with SessionBehavior.withAuth or SessionBehavior.authOnly, the TokenManager can automatically refresh auth tokens:
startAuthTokenManager() method creates an interval timerAUTH_FETCH_INTERVAL env var)When configured with SessionBehavior.withClientSession:
startClientSessionIdManager() method creates an interval timerCall renewTokens() to manually refresh tokens:
await tokenManager.renewTokens();
This method:
Pass bypassClient = true to skip client session ID update:
await tokenManager.renewTokens(true);
Call endSession() to terminate the session:
tokenManager.endSession();
This method:
initialized flag to falseThe isReady() method returns true only when all required tokens are valid:
┌─────────────────────────────────────────────────────────────┐
│ isReady() │
├─────────────────────────────────────────────────────────────┤
│ Returns FALSE if: │
│ - Session is not initialized │
│ - Required tokens don't exist (hasTokens() returns false) │
│ - Auth required but refresh/auth token invalid │
│ - Session token is invalid │
│ - Client session ID enabled but invalid │
│ │
│ Returns TRUE if: │
│ - All required tokens exist and are valid │
└─────────────────────────────────────────────────────────────┘
The TokenManager generates unique storage keys for each token based on the manager ID:
| Token | Key Pattern |
|---|---|
| Auth Token | woo-auth-token-{ID} |
| Session Token | woo-session-token-{ID} |
| Refresh Token | woo-refresh-token-{ID} |
| Client Credentials | woo-client-credentials-{ID} |
| Client Session ID | woo-client-session-{ID} |
| Client Session Expiry | woo-client-session-exp-{ID} |
The exact key format is determined by the createClientStorageKey() utility and can be customized via environment variables.
if (!tokenManager.isReady()) { await tokenManager.renewTokens(); } const { sessionToken, authToken } = tokenManager.getTokens(); // Make your GraphQL request
try { const result = await makeGraphQLRequest(); } catch (error) { if (isAuthenticationError(error)) { await tokenManager.renewTokens(); // Retry the request } }
async function logout() { // Call your logout mutation await logoutMutation(); // End the token manager session tokenManager.endSession(); // Redirect to home or login page router.push('/'); }