Clerk Production Flow
useAuth().getToken(), or a Next server route calls auth().getToken(). That returns a short-lived JWT.xwllm_... install token.Authorization: Bearer <xwllm token>. The server checks live entitlement on every request.This toy server accepts the development bearer token, the Clerk-shaped boundary-test token, or a real Clerk RS256 session JWT when launched in clerk-jwt mode. The pill models the payload shape Codex should receive.
Test Sign-Up Widget
For this live cycle, start the server in clerk-jwt mode with Clerk JWKS configured. The generated xwllm_... token is what Codex should keep.
React Token Fetch Shape
const { getToken } = useAuth()
const clerkJwt = await getToken()
const installToken = await fetch('/api/v1/llm-tokens', {
method: 'POST',
headers: {
Authorization: `Bearer ${clerkJwt}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ label: 'Codex install' })
})
Toy Clerk Token Shape
clerk-dev:user_123:workspace_123:http://localhost:3000
Generate Pill
What Codex Does With It
The pill is deliberately explicit: it names the OpenAPI document, the auth header, a first health check, and the hosted HTTP MCP config. A client can import the OpenAPI URL for REST tools or use the MCP block for hosted MCP tools.
GET /api/v1/tasks
Authorization: Bearer <token from pill>
Where State Lives
Clerk should hold identity and small metadata pointers, such as a local workspace id or Stripe customer id. The service database should hold install tokens, token hashes, scopes, revocation state, workspace membership, and the current Stripe entitlement decision.
Do not store raw xwllm_... tokens in Clerk metadata. Store only pointers or summaries there. The Haskell/Postgres side should remain the immediate source of truth for revocation and payment access.