> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keystoneos.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How session tokens work and how to create them securely.

## 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:

```typescript theme={null}
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

| Scope                | Description                                     |
| -------------------- | ----------------------------------------------- |
| `settlements:read`   | List and view settlements                       |
| `settlements:write`  | Create settlements, submit compliance decisions |
| `templates:read`     | List and view settlement templates              |
| `instructions:read`  | List and view instructions                      |
| `instructions:write` | Submit 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:

```typescript theme={null}
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:

```tsx theme={null}
<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):

```typescript theme={null}
// 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

```mermaid theme={null}
flowchart LR
    PB[Platform Backend] -->|M2M credentials| KS[KeyStone API]
    KS -->|Session token| PB
    PB -->|Session token| PF[Platform Frontend]
    PF -->|Session token| KS
    PF -.->|Never| M2M[M2M Credentials]
```

* 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.
