Handler.codeAuth (Deprecated)
Deprecated. Use Handler.deviceCode for new integrations. Handler.codeAuth remains available while existing CLI consumers migrate to /auth/device.
Creates a generic device-code handler used to bootstrap access keys for non-browser SDK contexts (CLIs, scripts). Mounts four endpoints under path:
POST {path}/code— create a pending device code from an SDK requestGET {path}/pending/:code— return the pending request bound to a code, for the approval UIPOST {path}/poll/:code— poll until the device code is authorized, then exchange for the granted access keyPOST {path}— authorize a pending device code with a signed key authorization
Each endpoint applies the configured rateLimit and reads JSON bodies up to maxBodyBytes.
Usage
import { Handler, CliAuth } from 'accounts/server'
const handler = Handler.codeAuth({
store: CliAuth.Store.memory(),
})Then plug handler into your server framework of choice:
createServer(handler.listener) // Node.js
Bun.serve({ fetch: handler.fetch }) // Bun
Deno.serve({ fetch: handler.fetch }) // Deno
app.all('*', c => handler.fetch(c.request)) // Elysia
app.use(handler.listener) // Express
app.use(c => handler.fetch(c.req.raw)) // Hono
export const GET = handler.fetch // Next.js
export const POST = handler.fetch // Next.jsParameters
chains
- Type:
readonly [Chain, ...Chain[]](fromviem) - Default:
[tempo, tempoModerato, tempoDevnet]
Supported chains. The handler resolves the client based on chain IDs carried by device-code requests and key authorizations. The first chain is used as the default when a request omits chainId.
import { } from 'viem/tempo/chains'
import { } from 'accounts/server'
const = .({
: [],
})maxBodyBytes
- Type:
number - Default:
16384
Maximum JSON request body size in bytes. Requests exceeding this limit are rejected with a 400 before parsing.
import { } from 'accounts/server'
const = .({
: 8_192,
})now
- Type:
() => number - Optional
Time source used for TTL evaluation. Defaults to Date.now. Useful for tests that need a deterministic clock.
import { } from 'accounts/server'
const = .({
: () => 1_700_000_000_000,
})path
- Type:
string - Default:
'/auth/pkce'
Path prefix for the code-auth endpoints.
import { } from 'accounts/server'
const = .({
: '/cli-auth',
})policy
- Type:
CliAuth.Policy - Optional
Validates and optionally rewrites requested defaults (expiry, spending limits) before the pending entry is stored. Use this to enforce server-side policy on what the SDK is allowed to ask for.
import { } from 'accounts/server'
const = .({
: {
: ({ }) => ({
: .( ?? 0, .(.() / 1000) + 3600),
}),
},
})random
- Type:
(size: number) => Uint8Array - Optional
Random byte generator used for device-code allocation. Defaults to the platform's crypto.getRandomValues. Override only for tests.
rateLimit
- Type:
CliAuth.RateLimit | false - Default:
CliAuth.RateLimit.memory({ max: 120, windowMs: 60_000 })
Shared rate limiter applied to every code-auth endpoint. Pass false to disable rate limiting entirely (not recommended in production).
import { , } from 'accounts/server'
const = .({
: ..(env.RATE_LIMITER),
})rateLimitKey
- Type:
(request: Request) => string - Default: Cloudflare's
cf-connecting-ipheader, falling back to'unknown'
Derives the rate-limit key from the incoming request. Override when fronting the handler with a different proxy that exposes the real client IP under another header.
import { } from 'accounts/server'
const = .({
: () => ..('x-real-ip') ?? 'unknown',
})store
- Type:
CliAuth.Store - Default:
CliAuth.Store.memory()
Device-code store. Persists pending, authorized, and consumed device-code entries. Use a durable backend in production so device codes survive process restarts.
import { , } from 'accounts/server'
const = .({
: ..(env.KV),
})transports
- Type:
Record<number, Transport>(fromviem) - Default:
http()for each configured chain
Transports keyed by chain ID. Override per chain to point at a private RPC endpoint.
import { } from 'viem'
import { } from 'viem/tempo/chains'
import { } from 'accounts/server'
const = .({
: {
[.]: ('https://rpc.tempo.xyz'),
},
})ttlMs
- Type:
number - Default:
600000(10 minutes)
Pending entry TTL in milliseconds. After this duration, pending device codes can no longer be authorized or polled.
import { } from 'accounts/server'
const = .({
: 5 * 60 * 1000,
})cors
- Type:
boolean | Cors - Default:
true
Inherited from from.Options. CORS configuration applied to every response.
headers
- Type:
Headers | Record<string, string> - Optional
Inherited from from.Options. Additional headers merged onto every response.