Authentication Tokens and Their Roles
Cloud Apps use two tokens that work together: an access token and a session token.
The access token authorizes your app to call JTL’s tenant-specific APIs. The session token identifies which merchant the request is for. Most JTL Cloud API requests need both: the access token goes in the
Authorization header, and the tenant ID (read from the verified session token) goes in the X-Tenant-ID header.
How They Fit Together
- Your frontend asks AppBridge for a session token.
- Your frontend sends the session token to your backend.
- Your backend verifies the session token and reads the
tenantIdfrom its payload. - Your backend separately fetches an access token using its client credentials.
- Your backend calls the JTL Cloud API with the access token in
Authorization: Bearerand the tenant ID inX-Tenant-ID.
Client Credentials: Getting an Access Token
Your backend authenticates with JTL’s Identity Provider using theCLIENT_ID and CLIENT_SECRET you received when registering your app in the Partner Portal.
Implementation
client_credentials grant type, and returns a JWT access token. This token authenticates your backend for API calls.
Token Response
A successful request returns:Caching and Refreshing Tokens
Access tokens are valid for approximately 24 hours. Requesting a new token on every API call adds latency and unnecessary load on the auth server. Cache the token and refresh it before it expires.This in-memory cache works for single-instance servers. If you’re running multiple instances (e.g., behind a load balancer), use a shared cache like Redis instead.
Session Tokens: Verifying the Frontend User
When your app runs inside the App Shell, the frontend gets a session token from the AppBridge. This token identifies who the user is and which tenant (merchant) they belong to. Your backend must verify this token before trusting it.How it Works
- Your frontend calls
appBridge.method.call('getSessionToken')to get a session token from the App Shell - The frontend sends this token to your backend (through the header)
- Your backend fetches JTL’s public keys (JWKS) and uses them to verify the token’s signature
- The verified payload contains the
tenantId,userId, andtenantSlug
Session Token Payload
A decoded session token contains:Implementation
Wiring it Together: The connect-tenant Route
The connect-tenant pattern ties both flows together. Your frontend gets a session token, sends it as a header (X-Session-ID) to your backend, and your backend verifies it and returns the tenant details.
Calling from the Frontend
Your frontend sends the session token to this route after the AppBridge initializes:Tenant Mapping
When a merchant installs your app, you need to store a record linking their JTL tenant ID to your app’s internal state. Without this mapping, your backend has no way to associate future requests. In-memory storage works in development but is wiped on every restart and does not survive multiple server instances. Use a persistent store from the start.What to Store
At minimum, persist the following on install:
If your app has its own user or account model, link the
tenantId to your internal record.
When to Write
Write the record in your/api/connect-tenant handler, after you verify the session token and before you return success to the frontend. Use an upsert rather than an insert: the same merchant may reinstall your app, and a duplicate-key error on reinstall is a poor experience.
A minimal PostgreSQL schema:
ON CONFLICT clause handles reinstalls cleanly.
When to Read
On every incoming request from your frontend, extract the tenant ID from the verified session token and look up your internal record:What Not to Do
A few anti-patterns cause most tenant-mapping bugs in production. Avoid each of these from the start.Token Lifecycle
Understanding when tokens expire and how to handle expiry prevents intermittent auth failures in production.Access Tokens
Access tokens from the client credentials flow expire after approximately 24 hours (86399 seconds). Your backend should cache and reuse the token, refreshing it before expiry. See the token caching example above. If an API call returns401 Unauthorized, clear your cached token and request a new one before retrying:
Session Tokens
Session tokens from the AppBridge are short-lived. If your frontend holds a session token too long, verification will fail on the backend. Request a fresh session token before each backend call, or at minimum before operations that require verified identity:Common Authentication Errors
These are the most frequent authentication issues and how to resolve them.JWKS fetch fails with 401
JWKS fetch fails with 401
The JWKS endpoint requires a valid access token in the
Authorization header. Make sure you’re passing Bearer <access_token>, not the session token or client credentials. If the access token itself is expired, refresh it first.What’s Next
Using Platform APIs
Call the JTL Cloud and JTL-Wawi REST and GraphQL APIs with your authenticated tokens.
App Shell & UI Integration
Reference for the manifest, AppBridge API, and Platform UI components.
Best Practices
Production patterns for token caching, error handling, and security.