Docs /api/tokens

API Tokens

API tokens let you authenticate programmatic requests to izri without using cookies or browser sessions.

Creating a Token

Use the tokens.createToken tRPC mutation. You must be authenticated with a session first.

const result = await trpc.tokens.createToken.mutate({
  name: 'CI pipeline token',
  expiresIn: 7 * 24 * 3600, // 7 days in seconds (optional)
  scopes: [],                 // reserved for future use
})

// Store result.rawToken immediately — it will NOT be shown again
console.log(result.rawToken) // izri_<64 hex chars>

The raw token is returned exactly once. If you lose it, revoke the old token and create a new one.


Using a Token in Requests

Pass the raw token as a Bearer header on any tRPC or REST request:

Authorization: Bearer izri_<your-token>

tRPC via HTTP

curl -X POST https://your-api/trpc/projects.listProjects \
  -H "Authorization: Bearer izri_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"json": {}}'

tRPC client (TypeScript)

import { createTRPCClient, httpBatchLink } from '@trpc/client'
import type { AppRouter } from '@izri/trpc/routers'

const trpc = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'https://your-api/trpc',
      headers: () => ({
        Authorization: `Bearer ${process.env.API_TOKEN}`,
      }),
    }),
  ],
})

Listing Tokens

const { tokens } = await trpc.tokens.listTokens.query()
// Returns metadata only — no raw token hashes

Each token object:

{
  id: string
  name: string
  createdAt: Date
  expiresAt: Date | null
  lastUsedAt: Date | null
  scopes: string[]
}

Revoking a Token

await trpc.tokens.revokeToken.mutate({ tokenId: 'TOKEN_ID' })

Revoked tokens are immediately rejected on all subsequent requests. There is no "soft delete" — the record is removed from the database.


Rotating a Token

Rotation atomically creates a new token and revokes the old one. Use this for credential rotation without downtime:

const result = await trpc.tokens.rotateToken.mutate({
  tokenId: 'OLD_TOKEN_ID',
  newName: 'Rotated token',    // optional
  expiresIn: 86400,            // optional
})

// Update your secret store with result.rawToken before the old one stops working

Expiry Handling

  • If expiresIn is omitted, the token never expires.
  • Expired tokens return HTTP 401 (UNAUTHORIZED) just like invalid tokens.
  • lastUsedAt is updated on every successful validation.
  • It is recommended to set an expiry for tokens used in CI or third-party integrations.

Security Best Practices

Practice Recommendation
Store tokens in secrets Use environment variables or a secrets manager (e.g. Vault, GitHub Secrets). Never commit raw tokens to source control.
Set expiry Prefer short-lived tokens (days/weeks) over non-expiring ones.
Rotate regularly Use rotateToken on a schedule (e.g. every 90 days).
Least privilege Future scopes field will allow restricting tokens to specific operations.
Revoke promptly If a token is leaked, revoke it immediately via revokeToken.
One token per use case Give each CI job, integration, or service its own named token so you can revoke individually.

Token Format

Tokens have the form: izri_<64 lowercase hex chars> (66+ chars total).

The prefix izri_ allows automated secret scanners (e.g. GitHub secret scanning, truffleHog) to detect leaked tokens.

The database stores a SHA-256 hash of the token. The raw token is never logged or persisted after the initial creation response.


Endpoints Summary

Procedure Type Auth required Description
tokens.createToken mutation ✅ Session Create a new token (raw shown once)
tokens.listTokens query ✅ Session List your tokens (no raw values)
tokens.revokeToken mutation ✅ Session Delete a token by ID
tokens.rotateToken mutation ✅ Session Atomically rotate a token

Reading this with an agent? /docs/api/tokens.md serves the raw markdown.

All docs