Skip to main content

Session Tokens

KeyStone Elements uses session tokens for browser-safe API access. These are short-lived, scoped JWTs issued by the KeyStone API, separate from the M2M credentials your backend uses.

Why Not Use M2M Credentials Directly?

M2M credentials (client_id + client_secret) have full API access for your environment. Exposing them in browser code would let anyone with DevTools access your entire settlement data and create/modify settlements on your behalf. Session tokens solve this by being:
  • Short-lived - 1 hour default (configurable 1 min to 24 hours)
  • Scoped - Limited to specific permissions (e.g., only settlements:read)
  • Revocable - Can be invalidated immediately via API
  • Auditable - Carry metadata about which end-user is acting

Creating Session Tokens

Your backend creates session tokens by calling POST /v1/sessions with M2M authentication:
import { createSessionToken } from '@keystoneos/node';

const session = await createSessionToken(keystoneClient, {
  scopes: ['settlements:read', 'settlements:write'],
  expiresIn: 3600, // 1 hour
  metadata: { userId: 'usr-123', email: 'trader@acme.com' },
});
// session.sessionToken -> pass this to the frontend

Available Scopes

ScopeDescription
settlements:readList and view settlements
settlements:writeCreate settlements, submit compliance decisions
templates:readList and view settlement templates
instructions:readList and view instructions
instructions:writeSubmit and cancel instructions

Scoping to Specific Settlements

You can restrict a session token to specific settlement IDs. This is useful when a trader should only see their own settlement:
const session = await createSessionToken(keystoneClient, {
  scopes: ['settlements:read'],
  settlementIds: ['a1b2c3d4-e5f6-7890-abcd-ef1234567890'],
  metadata: { userId: 'usr-123' },
});
The token holder can only access settlements in the settlementIds list. Attempts to access other settlements return 403.

Token Refresh

Session tokens expire. The KeystoneProvider supports automatic refresh via the onTokenExpired callback:
<KeystoneProvider
  sessionToken={token}
  onTokenExpired={async () => {
    // Call your backend to create a fresh token
    const res = await fetch('/api/keystone/session', { method: 'POST' });
    const data = await res.json();
    return data.token; // Return the new token string
  }}
>
The token manager refreshes 60 seconds before expiry to avoid interruptions. Concurrent refresh requests are deduplicated.

Revoking Tokens

Revoke a session token immediately (e.g., on user logout):
// From your backend
await keystoneClient.delete(`/v1/sessions/${tokenId}`);
Revoked tokens are rejected on the next API call, even if they haven’t expired yet.

Security Model

  • M2M credentials stay on your backend. Never sent to the browser.
  • Session tokens are the only auth mechanism in the browser.
  • Each session token is tied to a platform and environment.
  • The KeyStone API validates the token on every request and checks revocation status.