Authentication
Sesamy uses Auth0-compatible authentication to provide industry-standard, secure API access. You can integrate using any Auth0-compatible SDK.
Authentication Methods
Sesamy supports different authentication flows depending on your use case:
Management API - Client Credentials Flow
For server-to-server authentication to the Management API, use the Client Credentials flow.
Best for: Backend services, administrative tasks, server-side integrations
Apps & Websites - Authorization Code Flow
For user-facing applications and websites, use the Authorization Code flow with support for PKCE, cookie sessions, and refresh tokens.
Best for: Web applications, single-page applications, native mobile apps
Apps & Websites - Cookie-Based (BFF / Token Handler)
For publishers deploying Sesamy on a custom domain (e.g. app.yoursite.com), the API proxy implements the Token Handler pattern. The API proxy acts as the OAuth client — it completes the login flow server-side and stores encrypted tokens in HttpOnly cookies. JavaScript never sees a raw token.
Best for: Custom-domain integrations, high-security paywalls, sites where XSS token theft is unacceptable
Learn more about BFF Authentication →
Quick Examples
Management API - Client Credentials Flow
Get a token for server-to-server authentication:
curl -X POST https://token.sesamy.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "audience=https://api.sesamy.com"
# Use the access token
curl -X GET https://api.sesamy.com/management/v1/... \
-H "Authorization: Bearer ACCESS_TOKEN"Apps & Websites - Authorization Code Flow (with PKCE)
For web and mobile applications:
# Step 1: Redirect user to authorization endpoint
https://token.sesamy.com/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
response_type=code&
scope=openid profile email&
code_challenge=CHALLENGE&
code_challenge_method=S256
# Step 2: Exchange code for token
curl -X POST https://token.sesamy.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "code=AUTH_CODE" \
-d "code_verifier=VERIFIER" \
-d "redirect_uri=https://yourapp.com/callback"
# Use the access token
curl -X GET https://api.sesamy.com/client/v1/profile \
-H "Authorization: Bearer ACCESS_TOKEN"Cookie-Based (BFF) Authentication
The Sesamy API proxy implements the Token Handler pattern — a BFF (Backend-for-Frontend) approach to authentication where the API acts as the OAuth client and stores tokens in HttpOnly cookies instead of exposing them to JavaScript.
How It Works
The API proxy is the OAuth client. It runs the Authorization Code + PKCE flow server-side and hands the browser only HttpOnly cookies — JavaScript never touches a token. The diagram below traces a full login and one authenticated API call. acme is the vendor ID; api.yoursite.com is your custom domain (same eTLD+1 as the page).
Step by step:
- User clicks Login → browser navigates to
https://api.yoursite.com/auth/acme/login - API proxy generates PKCE, stores the verifier + CSRF state in the encrypted
__Host-auth-statecookie, and redirects tohttps://token.sesamy.com/authorizewithredirect_uri=https://api.yoursite.com/auth/acme/callback. Anylogin_hint/ui_localesride along. - User authenticates at the token service
- Token service redirects back to
https://api.yoursite.com/auth/acme/callbackwith the auth code - API proxy verifies the CSRF state, exchanges the code for tokens server-side, encrypts them with a per-vendor key, and sets the cookies (see Cookie Architecture below)
- Browser is redirected back to your SPA — cookies are set, JS never touched a token
- sesamy-js sees the
sesamy_is_authenticatedhint cookie and calls/auth/userinfoto hydrate the session - All subsequent API calls include cookies automatically (
credentials: include); the proxy decryptsat, refreshes via__Host-rtwhen expired, and forwardsAuthorization: Bearer <at>upstream
Cookie Architecture
This is the canonical reference for every cookie the BFF sets. The two token cookies (at, __Host-rt) are encrypted with a per-vendor AES-256-GCM key; the rest are plaintext hints.
| Cookie | Set when | HttpOnly | SameSite | Domain | Lifetime | Purpose |
|---|---|---|---|---|---|---|
at | callback | ✅ | Lax | .yoursite.com | access token's expires_in (typ. 1h) | Encrypted access token |
__Host-rt | callback | ✅ | Strict | — (__Host-) | 30 days | Encrypted refresh token |
sesamy_is_authenticated | callback | ❌ | Lax | .yoursite.com | 30 days | JS-readable session hint — gates the /auth/userinfo call so an anonymous visitor makes no auth request |
sesamy_cid | callback | ❌ | Lax | .yoursite.com | 30 days | Vendor/client ID hint — lets the proxy derive the per-vendor decryption key without an upstream lookup |
__Host-auth-state | login | ✅ | Lax | — (__Host-) | 10 min | Encrypted PKCE verifier + CSRF state + returnTo, consumed at the callback |
Key points:
__Host-prefix (__Host-rt,__Host-auth-state) forcesSecure,Path=/, and noDomain— the browser will only send these back to the API proxy itself, never to a sibling subdomain. Onlocalhost(insecure) the proxy falls back to a plainrt/auth-statecookie because__Host-requires HTTPS.atis scoped to the top-level domain (Domain=.yoursite.com) so it rides along on same-site API calls; the refresh token deliberately is not.- Only
sesamy_is_authenticatedandsesamy_cidare readable by JS — and neither is a token. They are hints that let sesamy-js skip needless network calls.
Enabling BFF Mode in sesamy-js
Set auth.useHttpCookies: true in your configuration. No @auth0/auth0-spa-js script is needed:
<script type="application/json" id="sesamy-js">
{
"clientId": "your-vendor-id",
"vendorId": "your-vendor-id",
"auth": {
"useHttpCookies": true
},
"api": {
"namespace": "sesamy",
"endpoint": ""
}
}
</script>Setting api.endpoint to "" makes sesamy-js use relative URLs (/entitlements, /contracts, etc.) so all requests stay on the same origin and flow through your reverse proxy or Vite dev server — ensuring cookies are scoped correctly.
Prerequisites
The Token Handler is configured per-vendor via the management API (PUT /management/vendors/:vendorId/token-handler). The entry requires:
clientId— your Sesamy vendor/client IDauthHostname— optional, used only for federated logout redirect
Because the vendor ID is embedded in the login and callback URLs, no hostname scanning is required — the proxy resolves vendor settings directly from the path.
Auth0 callback URL
You must add https://api.yoursite.com/auth/<vendorId>/callback to the Allowed Callback URLs list in your Auth0 application settings. For local development add http://localhost:8787/auth/<vendorId>/callback.
Security Properties
| Property | Value |
|---|---|
| Token exposure to JS | ✅ None — HttpOnly cookies only |
| XSS token theft | ✅ Immune |
| CSRF | ✅ Mitigated by SameSite=Lax/Strict |
| Token storage | AES-256-GCM encrypted, server-side per-vendor key |
| Session refresh | Automatic — refresh token rotated on each use |
| Cross-domain SSO | ❌ Not supported (session is domain-bound) |
Safari ITP and the 7-Day Cookie Cap
Safari's Intelligent Tracking Prevention (ITP) caps the lifetime of cookies set by cross-site responses to 7 days. This means:
- ✅ Custom domain (
api.yoursite.com+yoursite.com): both are on the same eTLD+1, so cookies are classified as first-party. The 7-day cap does not apply, and refresh tokens survive for their full 30-day lifetime. - ❌ No custom domain (
api2.sesamy.com+yoursite.com): the API is on a different domain, so Safari classifies theSet-Cookieresponse as cross-site. Cookies are capped at 7 days, causing users to be logged out weekly.
This is the primary reason the BFF pattern requires a custom domain on the same eTLD+1 as your site. If you cannot use a custom domain, use the standard Authorization Code + PKCE flow with refresh tokens instead.
Session Management
Cookie Sessions (Custom Domains)
If you're using a custom domain with the BFF pattern, sessions are managed entirely via HttpOnly cookies. No client-side token storage is needed.
Token Refresh (All Domains)
If you're not using custom domains, use refresh tokens to maintain user sessions:
curl -X POST https://token.sesamy.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=YOUR_CLIENT_ID" \
-d "refresh_token=REFRESH_TOKEN"Security Best Practices
Important
Never expose your client secrets in client-side code or public repositories. Always use PKCE for public clients (SPAs, native apps).
- Store secrets securely: Use environment variables or secure vaults for sensitive credentials
- Use HTTPS: Always use HTTPS for all authentication endpoints
- Enable PKCE: Use PKCE for all public clients (SPAs, native apps) to prevent authorization code interception
- Validate tokens: Verify token signatures and expiration on your backend
- Rotate secrets: Regularly rotate client secrets in your dashboard
- Use appropriate scopes: Request only the scopes your application needs
Auth0-Compatible SDKs
Since Sesamy uses Auth0-compatible authentication, you can use any Auth0-compatible SDK:
Next Steps
- API Keys - Management API credentials and setup
- OAuth 2.0 - Complete authorization flow guide
- JWT Tokens - Understanding and validating tokens