Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.commercengine.io/docs/llms.txt

Use this file to discover all available pages before exploring further.

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 { createStorefront } from "@commercengine/storefront";

const sdk = createStorefront({
  storeId: "your-store-id",
  apiKey: "your-api-key",
  // No tokenStorage provided = manual mode
});

Authentication Flow

1

Get anonymous token

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

if (data) {
  // Manually set tokens
  await sdk.setTokens(data.access_token, data.refresh_token);
}
2

Login with credentials

const { data: loginData } = await sdk.auth.loginWithPassword({
  email: "user@example.com",
  password: "password"
});

if (loginData) {
  // Update tokens after login
  await sdk.setTokens(loginData.access_token, loginData.refresh_token);
}
3

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 from the API
const { data: userData } = await sdk.auth.retrieveUser();
const user = userData?.user;
const userId = user?.id;

Automatic Token Management

Recommended for production applications. Handles token refresh, storage, and cleanup automatically.

Token Storage Options

Browser localStorage Storage

import { createStorefront }, { BrowserTokenStorage } from "@commercengine/storefront";

const sdk = createStorefront({
  storeId: "your-store-id",
  apiKey: "your-api-key",
  tokenStorage: new BrowserTokenStorage("myapp_") // Optional prefix
});
Features:
  • ✅ Persists across browser sessions
  • ✅ Automatic token refresh
  • ✅ Cross-tab synchronization
  • ✅ Works with SPA frameworks (React, Vue, Angular)
import { CookieTokenStorage } from "@commercengine/storefront";

const sdk = createStorefront({
  storeId: "your-store-id",
  apiKey: "your-api-key",
  tokenStorage: new CookieTokenStorage({
    prefix: "myapp_",
    maxAge: 7 * 24 * 60 * 60, // 7 days
    secure: true,
    sameSite: "Lax"
  })
});
Features:
  • ✅ SSR/SSG compatible
  • ✅ Server and client access
  • ✅ Cross-subdomain sharing
  • ✅ Automatic expiry handling

Memory Storage (Server-Side)

import { MemoryTokenStorage } from "@commercengine/storefront";

const sdk = createStorefront({
  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";

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 = createStorefront({
  storeId: "your-store-id",
  apiKey: "your-api-key",
  tokenStorage: new RedisTokenStorage(redisClient, userId)
});

Authentication Patterns

Anonymous to Authenticated Flow

import { createStorefront }, { BrowserTokenStorage } from "@commercengine/storefront";

const sdk = createStorefront({
  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: "user@example.com", 
    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 = createStorefront(getSDKConfig());

Token Lifecycle Events

Handling Token Updates

const sdk = createStorefront({
  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 = createStorefront({
  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 = createStorefront({
  storeId: "store-id",
  apiKey: "api-key",
  // No tokenStorage = manual management
});

Security Best Practices

  1. Use secure cookies in production:
const tokenStorage = new CookieTokenStorage({
  secure: true,      // HTTPS only
  sameSite: "Lax",   // CSRF protection
  httpOnly: false    // Required for client access
});
  1. Environment-specific configuration:
const isProduction = process.env.NODE_ENV === "production";

const sdk = createStorefront({
  // ... other config
  tokenStorage: new CookieTokenStorage({
    secure: isProduction,
    domain: isProduction ? ".mysite.com" : undefined
  })
});
  1. Handle token events properly:
const sdk = createStorefront({
  // ... 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:

React Integration

Context providers, hooks, and component patterns for React SPAs

Next.js Integration

SSR, Server Actions, and automatic cookie-backed token management

TanStack Start Integration

Server functions, route loaders, and pre-rendering

Astro Integration

SSR pages, API routes, middleware, and static prerendering

SvelteKit Integration

Server load functions, form actions, hooks, and universal loads

Node.js Integration

Server-side patterns and background job authentication
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.