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

# Signed Tokens (GatelitSigned)

> Your backend issues a short-lived HMAC-signed token per user. The frontend uses it for one request, then fetches a fresh one.

The `GatelitSigned` scheme lets your backend act as the token authority. Your server signs a compact JWT using your `GATELIT_SIGNING_SECRET`, returns it to the frontend, and the frontend includes it in the `Authorization` header. The gateway verifies the HMAC signature — no database lookup required.

<Note>
  Tokens expire after their TTL (default 60 seconds). Your frontend should fetch a fresh token before each request rather than caching one for reuse.
</Note>

## How it works

<Steps>
  <Step title="Install the SDK">
    Install `@gatelit/sdk` in your backend project.

    ```bash theme={null}
    npm install @gatelit/sdk
    ```
  </Step>

  <Step title="Create a token endpoint">
    Add a server route that authenticates the current user and returns a signed token. The example below uses a Nuxt server route, but the same pattern applies to any Node.js or edge runtime (Next.js API routes, Express, Hono, etc.).

    ```ts theme={null}
    // server/api/ai-token.get.ts
    import { signToken } from "@gatelit/sdk/sign"

    export default defineEventHandler(async (event) => {
      const user = await requireUser(event) // your own auth middleware

      const token = await signToken(
        {
          sub: user.id,
          model: "openai/gpt-4o-mini",
          maxTokens: 500,
          ttl: 60,
        },
        process.env.GATELIT_SIGNING_SECRET!,
      )

      return { token }
    })
    ```
  </Step>

  <Step title="Use the token on the frontend">
    Pass a `getToken` callback to `GatelitClient`. The callback is called before every request, so the gateway always receives a fresh token.

    ```ts theme={null}
    import { GatelitClient } from "@gatelit/sdk"

    const client = new GatelitClient({
      gatewayUrl: "https://gateway.yourapp.com",
      getToken: async () => {
        const { token } = await fetch("/api/ai-token").then((r) => r.json())
        return { token, scheme: "GatelitSigned" }
      },
    })

    const response = await client.chat({
      model: "openai/gpt-4o-mini",
      messages: [{ role: "user", content: "Hello!" }],
    })

    console.log(response.content)
    ```
  </Step>
</Steps>

## `signToken` reference

```ts theme={null}
import { signToken } from "@gatelit/sdk/sign"

const token = await signToken(options: SignedTokenOptions, secret: string): Promise<string>
```

`signToken` uses the Web Crypto API — available natively in Node.js 18+ and all edge runtimes (Cloudflare Workers, Vercel Edge, Deno).

### Options

| Option      | Type     | Required | Description                                                                                                                                     |
| ----------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `sub`       | `string` | Yes      | User identifier embedded in the token. Used for request attribution in logs.                                                                    |
| `model`     | `string` | No       | Restrict this token to a single model, e.g. `"openai/gpt-4o-mini"`. Requests using a different model will be rejected. Omit to allow any model. |
| `maxTokens` | `number` | No       | Cap the maximum output tokens for requests made with this token.                                                                                |
| `orgId`     | `string` | No       | Org ID to embed in the token. Used by the gateway to resolve org-scoped provider keys (BYOK).                                                   |
| `ttl`       | `number` | No       | Token lifetime in seconds. Defaults to `60`.                                                                                                    |

### Token format

The returned string is a compact dot-separated value: `base64url(header).base64url(payload).base64url(signature)` — structurally identical to a standard JWT.

## Using the token directly (without the SDK)

If you're not using `GatelitClient`, pass the token in the `Authorization` header manually:

```ts theme={null}
const { token } = await fetch("/api/ai-token").then((r) => r.json())

const response = await fetch("https://gateway.yourapp.com/v1/chat/completions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `GatelitSigned ${token}`,
  },
  body: JSON.stringify({
    model: "openai/gpt-4o-mini",
    messages: [{ role: "user", content: "Hello!" }],
  }),
})
```

## Token expiry and refresh

Tokens expire at the `exp` claim embedded in the payload (current time + `ttl`). When a token expires, the gateway returns a `401`. Your `getToken` implementation should always fetch a new token rather than reusing a cached one to avoid this.

<Tip>
  If your users make several requests in quick succession, consider implementing short-term caching in `getToken` (e.g. reuse a token until 5 seconds before its expiry) to avoid a round-trip on every request.
</Tip>
