Token Management
Why token management matters 🔐
Every storefront request to Elastic Path must carry a valid OAuth 2.0 access‑token in the Authorization header.
Because the shopper experience runs in the browser, the recommended flow is the implicit token grant: no client_secret travels to the client, yet the token still authorizes catalog, cart, and checkout calls.
With the new SDK (@epcc-sdk/sdks-shopper), token management is largely automated through configureClient or createShopperClient, but understanding the underlying process helps you customize behavior when needed.
For complete working implementations, check our Composable Frontend examples repository which includes ready-to-use patterns for:
1 · Automatic token management (recommended)
The SDK handles token generation automatically:
import { configureClient } from "@epcc-sdk/sdks-shopper";
// Configure once - tokens are managed automatically
export const client = configureClient(
{ baseUrl: "https://useast.api.elasticpath.com" },
{
clientId: process.env.CLIENT_ID,
storage: "localStorage" // or "cookie" or custom
}
);
// Make API calls - authentication happens automatically
import { getByContextAllProducts } from "@epcc-sdk/sdks-shopper";
const products = await getByContextAllProducts();
Manual token generation (when needed)
If you need direct control:
import { createShopperClient } from "@epcc-sdk/sdks-shopper";
const { client, auth } = createShopperClient(
{ baseUrl: "https://useast.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
// Manually get token
const token = await auth.getValidAccessToken();
console.log("Token:", token);
2 · Storage options with the SDK
The SDK supports multiple storage patterns out of the box:
localStorage (default for SPAs)
import { configureClient } from "@epcc-sdk/sdks-shopper";
export const client = configureClient(
{ baseUrl: "https://useast.api.elasticpath.com" },
{
clientId: process.env.CLIENT_ID,
storage: "localStorage" // Persists across tabs and refreshes
}
);
Cookie storage (better for SSR)
export const client = configureClient(
{ baseUrl: "https://useast.api.elasticpath.com" },
{
clientId: process.env.CLIENT_ID,
storage: "cookie",
cookieOptions: {
domain: ".yourdomain.com",
secure: true,
sameSite: "lax",
httpOnly: false // Set true if handling through server proxy
}
}
);
Custom storage adapter
export const client = configureClient(
{ baseUrl: "https://useast.api.elasticpath.com" },
{
clientId: process.env.CLIENT_ID,
storage: {
get: async (key) => {
// Your custom retrieval logic
return await customStore.get(key);
},
set: async (key, value) => {
await customStore.set(key, value);
},
remove: async (key) => {
await customStore.delete(key);
}
}
}
);
Complete examples on GitHub
- Local Storage Authentication Example - Implementation of client-side token storage
- Server Cookie Authentication Example - Implementation of server-side HttpOnly cookie pattern
Security note: localStorage is vulnerable to XSS exfiltration; if you control a server layer, prefer an HttpOnly cookie
3 · How the SDK attaches tokens
With configureClient or createShopperClient, tokens are automatically attached to all requests:
import { configureClient, getByContextAllProducts } from "@epcc-sdk/sdks-shopper";
// Configure once
const client = configureClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
// Token is automatically added to Authorization header
const products = await getByContextAllProducts();
// Header sent: Authorization: Bearer <token>
Adding custom headers with interceptors
After configuring the client, you can add interceptors:
import { configureClient } from "@epcc-sdk/sdks-shopper";
export const client = configureClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
// Add interceptors after configuration
client.interceptors.request.use((request, options) => {
// SDK already added the implicit token
// Add any additional headers
request.headers.set("X-Custom-Header", "value");
return request;
});
Managing both Implicit and Account tokens
As described in the Authentication Concepts guide, many storefront experiences require both an implicit token and an Account Management Authentication token. With the new SDK:
import { configureClient } from "@epcc-sdk/sdks-shopper";
export const client = configureClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
// Add account token via interceptor
client.interceptors.request.use((request, options) => {
// The SDK already handles the implicit token
// Add account token for personalized shopper access
const accountToken = localStorage.getItem("ep_account_token");
if (accountToken) {
request.headers.set("EP-Account-Management-Authentication-Token", accountToken);
}
return request;
});
This pattern ensures that:
- The implicit token is automatically managed by the SDK
- The Account Management Authentication token is added when available
- Both tokens are sent with appropriate headers
Server‑side with Next.js
// app/api/products/route.ts
import { createShopperClient } from "@epcc-sdk/sdks-shopper";
import { cookies } from "next/headers";
export async function GET() {
const cookieStore = cookies();
const token = cookieStore.get("ep_implicit_token");
const { client } = createShopperClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{
clientId: process.env.EPCC_CLIENT_ID,
storage: {
get: async () => token?.value,
set: async () => {}, // Handled by server
remove: async () => {}
}
}
);
const { getByContextAllProducts } = await import("@epcc-sdk/sdks-shopper");
const products = await getByContextAllProducts();
return Response.json(products);
}
4 · Token expiration and refresh
The SDK automatically handles token expiration and refresh:
- Implicit tokens expire in approximately 1 hour (3600 seconds)
- Account Management tokens have configurable expiration times
- Automatic refresh happens before expiry (default: 60 seconds before expiration)
How automatic refresh works
import { configureClient } from "@epcc-sdk/sdks-shopper";
// The SDK automatically:
// 1. Tracks token expiry time
// 2. Refreshes 60 seconds before expiration
// 3. Retries on 401 errors
// 4. Updates stored tokens (key: _store_ep_credentials)
export const client = configureClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
Checking token state
import { createShopperClient } from "@epcc-sdk/sdks-shopper";
const { client, auth } = createShopperClient(
{ baseUrl: "https://euwest.api.elasticpath.com" },
{ clientId: process.env.CLIENT_ID }
);
// Get current token (triggers fetch/refresh if needed)
const token = await auth.getValidAccessToken();
// Get current token without triggering refresh
const snapshot = await auth.getSnapshot();
// Force token refresh
const newToken = await auth.refresh();
// Clear authentication if needed
await auth.clear();
For advanced token refresh strategies and manual control, see the Token Refresh guide.
Summary
The new Elastic Path SDK (@epcc-sdk/sdks-shopper) dramatically simplifies token management:
- Automatic token handling -
configureClientmanages the complete token lifecycle - Flexible storage - Built-in support for localStorage, cookies, or custom adapters
- Seamless authentication - Tokens are automatically added to all API requests
- Account token support - Easy integration of both implicit and account tokens
For most use cases, simply using configureClient provides complete token management. Only implement custom logic when you have specific requirements beyond the SDK's automatic handling.
By combining the SDK's automatic token management with the patterns from the Token Refresh guide, you'll create a robust authentication system with minimal code.