Sessions & Authentication
Session tokens are short-lived HS256 JWTs that prove a request originated from a real merchant session inside the LaunchMyStore admin. Your app’s backend verifies them with the sameclientSecret LaunchMyStore stored
when the merchant installed the app — no shared session store, no
round-trips back to LaunchMyStore for the common case.
Flow
The crucial property: the JWT signature is your proof. Anyone in possession ofclientSecret can mint a token; the secret lives only on
the LaunchMyStore host and on your backend. Your frontend never sees it.
The minting endpoint (
POST /api/apps/session-token, host-internal)
requires only the app apiKey plus the admin session. A domainSlug
field is optional — the host resolves the shop host from the
backend’s authoritative storeURL, so tokens mint correctly even when
the admin session has no domainslug cookie.Getting a Token
Vanilla SDK
App.getSessionToken() is a thin wrapper over
dispatchAndWait('SESSION_TOKEN_REQUEST') — it round-trips every call
and does not cache. For caching + auto-refresh-when-near-expiry, use
the SessionToken helper class or the useSessionToken React hook.React hook
useAuthenticatedFetch
The shortest path — afetch wrapper that injects the Authorization
header for you:
Token Structure
Token Lifecycle
- Lifetime: tokens expire 24 hours after issuance (
exp = iat + 86400). Don’t hard-code this — always readexpfrom the token and refresh when it’s near expiry. - Caching: the SDK’s
SessionToken.create(app)and theuseSessionTokenhook keep the token in memory until 30 seconds before expiry — callgetToken()before every authenticated request and the helper does the right thing. - Forced refresh: call
session.refresh()(vanilla) orrefresh()(hook) to drop the cache and request a new token immediately. Useful after permission changes or before a long-running operation.
Verifying Tokens
Always verify on your backend with the sameclientSecret you received
during OAuth install.
Node.js (Express)
Use
issuer: 'https://launchmystore.io' (the actual claim). Earlier
docs showed issuer: 'launchmystore' — that string will fail
verification.Python (Flask)
PHP (firebase/php-jwt)
Common Patterns
Manual fetch wrapper (vanilla SDK)
React Query
Axios
Error Handling
app.getSessionToken() / session.getToken() reject with the SDK’s
generic Error shape — there is no error.code. Branch on
error.message if you need to distinguish causes:
Debugging
atob-decoding the middle segment of a JWT is safe for local inspection
(it skips signature verification — never trust it for auth decisions):
peek(token).exp - Date.now()/1000
to see if you have a clock-skew problem.
Security Best Practices
Never embed clientSecret in your frontend
Never embed clientSecret in your frontend
The secret lives on the LaunchMyStore host (to mint tokens) and your
backend (to verify them). If you put it in JavaScript that ships to
the browser, anyone can forge a token.
Always scope by sub
Always scope by sub
Every backend query that touches merchant data MUST be scoped by
claims.sub. Treat session tokens like row-level security tokens.Verify aud and iss explicitly
Verify aud and iss explicitly
The signature alone isn’t enough — a token issued for another app
(different
aud) or by a different host (different iss) is a valid
JWT but a wrong one.HTTPS only
HTTPS only
Tokens grant access to merchant data — transmit only over TLS.
Don't log tokens
Don't log tokens
The signature is private; never write tokens to logs, exception
reports, or telemetry.
See Also
- Authentication — OAuth flow for getting
clientSecret. - Actions Reference —
SESSION_TOKEN_REQUESTpayload shape. - React Hooks —
useSessionToken,useAuthenticatedFetch,useAppQuery,useAppMutation.