The CommerceEngine SDK provides two sophisticated approaches to token management, designed to handle everything from simple prototyping to production-scale applications with automatic token refresh and persistence.
Overview
Manual Token Management Simple approach where you handle token storage and refresh logic yourself
Automatic Token Management Production-ready approach with automatic token refresh, persistence, and cleanup
Manual Token Management
Perfect for prototyping, testing, or when you need full control over token handling.
Basic Setup
import StorefrontSDK from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
// No tokenStorage provided = manual mode
});
Authentication Flow
Get anonymous token
const { data , error } = await sdk . auth . getAnonymousToken ();
if ( data ) {
// Manually set tokens
await sdk . setTokens ( data . access_token , data . refresh_token );
}
Login with credentials
const { data : loginData } = await sdk . auth . loginWithPassword ({
email: "[email protected] " ,
password: "password"
});
if ( loginData ) {
// Update tokens after login
await sdk . setTokens ( loginData . access_token , loginData . refresh_token );
}
Handle token refresh manually
// Check if user is logged in
const isLoggedIn = await sdk . isLoggedIn ();
if (! isLoggedIn ) {
// Token might be expired, try to refresh
const refreshToken = getStoredRefreshToken (); // Your storage logic
const { data : refreshData } = await sdk . auth . refreshToken ({
refresh_token: refreshToken
});
if ( refreshData ) {
await sdk . setTokens ( refreshData . access_token , refreshData . refresh_token );
}
}
Manual Mode Methods
// Set tokens for all clients
await sdk . setTokens ( accessToken , refreshToken );
// Clear all tokens
await sdk . clearTokens ();
// Check authentication status
const isLoggedIn = await sdk . isLoggedIn ();
const isAnonymous = await sdk . isAnonymous ();
// Get user information
const userInfo = await sdk . getUserInfo ();
const userId = await sdk . getUserId ();
const customerId = await sdk . getCustomerId ();
Automatic Token Management
Recommended for production applications. Handles token refresh, storage, and cleanup automatically.
Token Storage Options
Browser localStorage Storage
Basic Usage With Callbacks import StorefrontSDK , { BrowserTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new BrowserTokenStorage ( "myapp_" ) // Optional prefix
});
import StorefrontSDK , { BrowserTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new BrowserTokenStorage ( "myapp_" ) // Optional prefix
});
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new BrowserTokenStorage ( "myapp_" ),
// Handle token lifecycle events
onTokensUpdated : ( accessToken , refreshToken ) => {
console . log ( "User authenticated successfully" );
// Optional: Update UI state, analytics, etc.
},
onTokensCleared : () => {
console . log ( "User logged out" );
// Optional: Redirect to login, clear user state, etc.
}
});
Features:
✅ Persists across browser sessions
✅ Automatic token refresh
✅ Cross-tab synchronization
✅ Works with SPA frameworks (React, Vue, Angular)
Cookie Storage (SSR Compatible)
Basic Setup Next.js Example import { CookieTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new CookieTokenStorage ({
prefix: "myapp_" ,
maxAge: 7 * 24 * 60 * 60 , // 7 days
secure: true ,
sameSite: "Lax"
})
});
import { CookieTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new CookieTokenStorage ({
prefix: "myapp_" ,
maxAge: 7 * 24 * 60 * 60 , // 7 days
secure: true ,
sameSite: "Lax"
})
});
// Perfect for Next.js applications
const sdk = new StorefrontSDK ({
storeId: process . env . NEXT_PUBLIC_STORE_ID !,
apiKey: process . env . NEXT_PUBLIC_API_KEY !,
tokenStorage: new CookieTokenStorage ({
prefix: "myapp_" ,
secure: process . env . NODE_ENV === "production" ,
domain: process . env . NODE_ENV === "production" ? ".mysite.com" : undefined
})
});
Features:
✅ SSR/SSG compatible
✅ Server and client access
✅ Cross-subdomain sharing
✅ Automatic expiry handling
Memory Storage (Server-Side)
import { MemoryTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new MemoryTokenStorage ()
});
// Perfect for:
// - Server-side API routes
// - Background jobs
// - Testing environments
Features:
✅ Fast in-memory access
✅ No persistence overhead
✅ Perfect for server environments
✅ Automatic cleanup on process end
Custom Token Storage
Implement the TokenStorage
interface for custom storage solutions:
import { TokenStorage } from "@commercengine/storefront-sdk" ;
class RedisTokenStorage implements TokenStorage {
constructor ( private redisClient : RedisClient , private userId : string ) {}
async getAccessToken (): Promise < string | null > {
return await this . redisClient . get ( `user: ${ this . userId } :access_token` );
}
async setAccessToken ( token : string ): Promise < void > {
await this . redisClient . setex ( `user: ${ this . userId } :access_token` , 3600 , token );
}
async getRefreshToken (): Promise < string | null > {
return await this . redisClient . get ( `user: ${ this . userId } :refresh_token` );
}
async setRefreshToken ( token : string ): Promise < void > {
await this . redisClient . setex ( `user: ${ this . userId } :refresh_token` , 86400 * 7 , token );
}
async clearTokens (): Promise < void > {
await this . redisClient . del ([
`user: ${ this . userId } :access_token` ,
`user: ${ this . userId } :refresh_token`
]);
}
}
// Use custom storage
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new RedisTokenStorage ( redisClient , userId )
});
Authentication Patterns
Anonymous to Authenticated Flow
import StorefrontSDK , { BrowserTokenStorage } from "@commercengine/storefront-sdk" ;
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new BrowserTokenStorage ( "myapp_" )
});
async function authenticateUser () {
// 1. Start with anonymous authentication
const { data : anonData } = await sdk . auth . getAnonymousToken ();
// 2. User browses anonymously, adds items to cart
await sdk . cart . createCart ({
items: [{ product_id: "product-123" , quantity: 1 }]
});
// 3. User decides to login
const { data : loginData } = await sdk . auth . loginWithPassword ({
email: "[email protected] " ,
password: "password"
});
// 4. SDK automatically updates tokens and maintains cart
// No manual token management required!
}
OTP Authentication Flow
async function otpLogin ( phone : string ) {
// 1. Initiate OTP login
const { data : otpData } = await sdk . auth . loginWithPhone ({
phone: phone ,
country_code: "+1" ,
register_if_not_exists: true
});
if (! otpData ) return ;
// 2. User enters OTP (from your UI)
const otp = await getUserOTPInput (); // Your UI logic
// 3. Verify OTP
const { data : authData } = await sdk . auth . verifyOtp ({
otp: otp ,
otp_token: otpData . otp_token ,
otp_action: otpData . otp_action
});
// 4. Tokens are automatically managed
if ( authData ) {
console . log ( "User authenticated successfully!" );
}
}
Multi-Environment Token Management
// Development/Staging/Production configuration
const getSDKConfig = () => {
const isProduction = process . env . NODE_ENV === "production" ;
return {
storeId: process . env . NEXT_PUBLIC_STORE_ID !,
environment: isProduction ? Environment . Production : Environment . Staging ,
apiKey: process . env . NEXT_PUBLIC_API_KEY !,
tokenStorage: new CookieTokenStorage ({
prefix: isProduction ? "prod_" : "dev_" ,
secure: isProduction ,
domain: isProduction ? ".mysite.com" : undefined ,
maxAge: isProduction ? 7 * 24 * 60 * 60 : 24 * 60 * 60 // 7 days prod, 1 day dev
}),
debug: ! isProduction ,
onTokensUpdated : ( accessToken , refreshToken ) => {
// Analytics or logging
if ( isProduction ) {
analytics . track ( "user_authenticated" );
}
}
};
};
const sdk = new StorefrontSDK ( getSDKConfig ());
Token Lifecycle Events
Handling Token Updates
const sdk = new StorefrontSDK ({
storeId: "your-store-id" ,
apiKey: "your-api-key" ,
tokenStorage: new BrowserTokenStorage (),
onTokensUpdated : ( accessToken , refreshToken ) => {
// Called when:
// - User logs in
// - Tokens are refreshed automatically
// - setTokens() is called manually
console . log ( "Tokens updated" );
// Update your application state
updateUserState ({ authenticated: true });
// Send to analytics
analytics . identify ( getUserIdFromToken ( accessToken ));
},
onTokensCleared : () => {
// Called when:
// - User logs out
// - Tokens are invalid and can't be refreshed
// - clearTokens() is called manually
console . log ( "Tokens cleared" );
// Update your application state
updateUserState ({ authenticated: false });
// Redirect to login
router . push ( "/login" );
}
});
JWT Utilities
The SDK provides utilities to extract information from tokens:
// Get user information from current token
const userInfo = await sdk . getUserInfo ();
// Returns: { userId: string, email?: string, customerId?: string, ... }
// Check authentication status
const isLoggedIn = await sdk . isLoggedIn (); // true if authenticated user
const isAnonymous = await sdk . isAnonymous (); // true if anonymous token
// Get specific user identifiers
const userId = await sdk . getUserId ();
const customerId = await sdk . getCustomerId ();
const customerGroupId = await sdk . getCustomerGroupId ();
Best Practices
✅ Production Recommendations
Always use automatic token management in production with appropriate storage for your environment.
// ✅ GOOD: Production setup
const sdk = new StorefrontSDK ({
storeId: process . env . NEXT_PUBLIC_STORE_ID !,
environment: Environment . Production ,
apiKey: process . env . NEXT_PUBLIC_API_KEY !,
tokenStorage: new CookieTokenStorage ({
prefix: "myapp_" ,
secure: true ,
sameSite: "Lax"
}),
onTokensUpdated: handleAuthSuccess ,
onTokensCleared: handleAuthFailure
});
// ❌ BAD: Manual management in production
const sdk = new StorefrontSDK ({
storeId: "store-id" ,
apiKey: "api-key" ,
// No tokenStorage = manual management
});
Security Best Practices
Use secure cookies in production :
const tokenStorage = new CookieTokenStorage ({
secure: true , // HTTPS only
sameSite: "Lax" , // CSRF protection
httpOnly: false // Required for client access
});
Environment-specific configuration :
const isProduction = process . env . NODE_ENV === "production" ;
const sdk = new StorefrontSDK ({
// ... other config
tokenStorage: new CookieTokenStorage ({
secure: isProduction ,
domain: isProduction ? ".mysite.com" : undefined
})
});
Handle token events properly :
const sdk = new StorefrontSDK ({
// ... config
onTokensCleared : () => {
// Clear sensitive data
clearUserCache ();
clearCartData ();
// Redirect to safe page
router . push ( "/" );
}
});
Framework Integration
For framework-specific token management patterns and implementation details, see our dedicated integration guides:
Token Management Summary : The SDK’s automatic token management handles all the complexity of authentication, token refresh, and storage, allowing you to focus on building your application features while ensuring a seamless user experience.