SeloraXDEVELOPERS

Session Token Flow

Session Token Flow

This page documents the complete lifecycle of session tokens for embedded apps, from the moment a merchant navigates to your app page through ongoing token refresh.

Overview

Session tokens are short-lived JWTs that authenticate embedded app iframes to the SeloraX platform API. They are:

  • Signed with HMAC-SHA256 using your app's session_signing_key
  • Valid for 10 minutes
  • Delivered via the App Bridge postMessage protocol
  • Verified server-side through the platform's session verification endpoint

Complete Flow

Step 1: Merchant Navigates to App

The merchant opens your app's page within the SeloraX dashboard (e.g., /22/settings/apps/messaging).

Step 2: Dashboard Requests Embed Parameters

The dashboard frontend calls the platform API to get the iframe URL and initial session token:

GET /api/apps/session/embed-params?app_id=X&store_id=Y

Step 3: Backend Generates Embed Data

The platform generates two things:

  1. HMAC-signed iframe URL — Your app's app_url with signed query parameters:

    https://app.example.com?store_id=22&host=<base64>&timestamp=<unix>&hmac=<sha256>
    
  2. JWT session token — Signed with your app's session_signing_key using HS256, with a 10-minute TTL.

Step 4: Dashboard Loads the Iframe

The dashboard sets the iframe src to the HMAC-signed URL. Your app begins loading.

Step 5: App Verifies HMAC Parameters

When your app loads, it should verify the HMAC signature on the URL parameters to confirm the request originated from SeloraX. This prevents unauthorized embedding.

Step 6: App Sends Ready Signal

Once loaded and verified, your app sends the handshake message:

window.parent.postMessage({ type: 'app-bridge:ready' }, '*');

Step 7: Dashboard Delivers Session Token

The dashboard responds with the session token:

// Dashboard sends:
iframe.contentWindow.postMessage({
  type: 'selorax:session-token',
  token: '<jwt>'
}, appOrigin);

Step 8: App Uses Token for API Calls

Your app includes the token in API requests:

Authorization: Bearer <session_token>

Flow Diagram

  Merchant                Dashboard               Platform API             Your App
     |                       |                         |                      |
     |-- opens app page ---->|                         |                      |
     |                       |-- GET embed-params ---->|                      |
     |                       |                         |-- generates HMAC URL |
     |                       |                         |-- generates JWT      |
     |                       |<-- { iframe_url, token }|                      |
     |                       |                         |                      |
     |                       |-- sets iframe src ---------------------------------->|
     |                       |                         |                      |
     |                       |                         |         verifies HMAC params
     |                       |                         |                      |
     |                       |<------------- app-bridge:ready ----------------|
     |                       |                         |                      |
     |                       |------------- selorax:session-token ----------->|
     |                       |                         |                      |
     |                       |                         |<-- API call + Bearer |
     |                       |                         |-- response --------->|

Token Refresh Cycle

Session tokens expire after 10 minutes. When your app receives a 401 Unauthorized from the API:

  1. App sends selorax:request-session-token via postMessage
  2. Dashboard calls POST /api/apps/session/session-token to generate a fresh JWT
  3. Dashboard delivers the new token via selorax:session-token
  4. App retries the failed request with the new token
  Your App                  Dashboard               Platform API
     |                         |                         |
     |-- API call + Bearer ----|------------------------>|
     |                         |                         |
     |<-- 401 Unauthorized ----|-------------------------|
     |                         |                         |
     |-- request-session-token |                         |
     |                         |-- POST session-token -->|
     |                         |<-- new JWT -------------|
     |                         |                         |
     |<-- selorax:session-token|                         |
     |                         |                         |
     |-- retry API call -------|------------------------>|
     |                         |                         |
     |<-- 200 OK --------------|-------------------------|

HMAC Verification (App Side)

When your app loads inside the iframe, verify the URL parameters to ensure the request came from SeloraX.

const crypto = require('crypto');
 
function verifyHmacParams(query, signingKey) {
  const { hmac, ...params } = query;
 
  // Sort parameters alphabetically and build the message string
  const message = Object.keys(params)
    .sort()
    .map(key => `${key}=${params[key]}`)
    .join('&');
 
  // Compute expected HMAC
  const expected = crypto
    .createHmac('sha256', signingKey)
    .update(message)
    .digest('hex');
 
  // Compare signatures
  if (hmac !== expected) return false;
 
  // Check timestamp is within 5-minute window
  const timestamp = parseInt(params.timestamp);
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - timestamp) > 300) return false;
 
  return true;
}

Parameters included in the HMAC:

ParameterDescription
store_idThe merchant's store ID
hostBase64-encoded dashboard host
timestampUnix timestamp (seconds) when the URL was generated
hmacSHA-256 HMAC of the sorted parameter string (excluded from signing input)

Session Token JWT Claims

The session token is a standard JWT (HS256) with these claims:

{
  "iss": "https://admin.selorax.io",
  "dest": "https://app.example.com",
  "aud": "sx_app_1b16e193a28d2640d2d9734dbf4907e8",
  "sub": "22",
  "sid": "2",
  "app_id": 2,
  "jti": "550e8400-e29b-41d4-a716-446655440000",
  "iat": 1708000000,
  "exp": 1708000600
}
ClaimDescription
issIssuer — the dashboard origin (from DASHBOARD_URL env var)
destDestination — your app's app_url
audAudience — your app's client_id
subSubject — the merchant's store_id
sidSession ID — the installation_id for this app+store
app_idYour app's numeric ID
jtiUnique token identifier (UUID)
iatIssued at timestamp
expExpiration timestamp (10 minutes from iat)

The token is signed with your app's session_signing_key using HMAC-SHA256 (HS256 algorithm).

Server-Side Token Verification

Your app's backend can verify session tokens by calling the platform's verification endpoint.

POST /api/apps/session/verify
Content-Type: application/json

{
  "session_token": "<jwt>",
  "client_id": "sx_app_...",
  "client_secret": "sx_secret_..."
}

Response (200 OK):

{
  "message": "Session token verified.",
  "data": {
    "store_id": 22,
    "installation_id": 2,
    "app_id": 2
  },
  "status": 200
}

This endpoint is rate limited to 300 requests per minute. Cache the verification result for the token's remaining lifetime to avoid hitting this limit.

Best Practices

  • Verify HMAC on every iframe load. Do not skip this step, even in development.
  • Cache verified token claims. After verifying a session token once, cache the result keyed by the token's jti or hash until its expiry.
  • Request new tokens proactively. If you know a token is close to expiry (e.g., 9 minutes old), request a fresh one before making API calls.
  • Handle the 401-refresh cycle gracefully. Queue pending requests while waiting for a new token, then replay them. Avoid requesting multiple tokens simultaneously.
  • Validate origins. Always check event.origin in your postMessage handler in production environments.