Token Codex — Claims, Scopes, and JWT Structure
The full JWT decoded from the Bearer token used by the desktop app — claims, scopes, and what each field enables
Token Codex — Claims, Scopes, and JWT Structure
Part of openai-research. Decoded from the real Bearer token captured by the bezetacil harness (2026-08-25, refreshed token).
Header
{"alg": "RS256", "kid": "mFnbD4V-KI0EXDyc4Q_vdanThEwG48vaIsuzKSJtn9s", "typ": "JWT"}
Payload (claims)
{
"aud": ["https://api.openai.com/v1"],
"client_id": "app_EMoamEEZ73f0CkXaXp7hrann",
"iss": "https://auth.openai.com",
"sub": "apple|000232.baec292476e74d26a842c381d383da52.1406",
"amr": ["urn:openai:amr:apple"],
"scp": ["openid", "profile", "email", "offline_access",
"api.connectors.read", "api.connectors.invoke"],
"session_id": "authsess_ESXHz0E0mXitXU3sRzGjVaoE",
"sl": true,
"jti": "4647d2d1…",
"pwd_auth_time": 1786649686695,
"https://api.openai.com/auth": {
"chatgpt_account_id": "aa06cafc-…",
"chatgpt_account_user_id": "user-3Qsjai6bWwak8NCEgerE8FRj__aa06cafc-…",
"chatgpt_user_id": "user-3Qsjai6bWwak8NCEgerE8FRj",
"chatgpt_plan_type": "plus",
"chatgpt_compute_residency": "no_constraint",
"localhost": true,
"poid": "org-hqTROhgAms22weYjAbomRTTY",
"user_id": "user-3Qsjai6bWwak8NCEgerE8FRj"
},
"https://api.openai.com/profile": {
"email": "…", "email_verified": true, "name": "Alef Oliveira"
},
"iat": 1787681149, "nbf": 1787681149, "exp": 1788545149
}
What each claim enables
| Claim | Effect |
|---|---|
aud: api.openai.com/v1 | the token talks to the API v1 (the chatgpt.com backends use this aud) |
amr: urn:openai:amr:apple | auth method: Apple ID (Sign in with Apple) |
scp: api.connectors.read + invoke | connectors scope — enables the chat submode plugins |
scp: offline_access | refresh token is issued (partial rotation) |
localhost: true | the session is local (desktop app, not web) |
sl: true | session locking active |
chatgpt_plan_type: plus | the plan — model/effort gating derives from this |
chatgpt_compute_residency: no_constraint | no compute region restriction |
poid: org-… | default organization |
exp - iat = 10 days | access token window (the 5-minute preemptive refresh covers with margin) |
OAuth scopes (the authorize request)
openid profile email offline_access + api.connectors.read + api.connectors.invoke — the last two are the connectors scopes that enable the chat submode plugins. The offline_access emits the refresh token.
TypeScript types (the token surface)
export interface JwtHeader {
alg: 'RS256'
kid: string // 'mFnbD4V-…' — 31 chars
typ: 'JWT'
}
export type AmrMethod = 'urn:openai:amr:apple' | string
export type ScopeName = 'openid' | 'profile' | 'email' | 'offline_access'
| 'api.connectors.read' | 'api.connectors.invoke' | string
export type PlanType = 'plus' | 'pro' | 'free' | 'unknown' | string
export type ComputeResidency = 'no_constraint' | string
/** The `https://api.openai.com/auth` claim (nested, capitalized URL key). */
export interface OpenAIAuthClaim {
chatgpt_account_id: string // 'aa06cafc-…'
chatgpt_account_user_id: string // 'user-…__aa06cafc-…'
chatgpt_user_id: string // 'user-…'
chatgpt_plan_type: PlanType
chatgpt_compute_residency: ComputeResidency
localhost: boolean // desktop app session (not web)
poid: string // default org id ('org-…')
user_id: string // 'user-…'
}
/** The access-token payload — the SAME shape for the app-server session and
* the A1 live authToken; the session_id is the WAF-recognized identity. */
export interface AccessTokenPayload {
aud: ['https://api.openai.com/v1']
client_id: 'app_EMoamEEZ73f0CkXaXp7hrann'
iss: 'https://auth.openai.com'
sub: `apple|${number}.${string}` // 'apple|000232.baec…1406'
amr: AmrMethod[]
scp: ScopeName[]
session_id: string // 'authsess_…' — per login session
sl: boolean
jti: string
pwd_auth_time: number
['https://api.openai.com/auth']: OpenAIAuthClaim
['https://api.openai.com/profile']: {
email: string
email_verified: boolean
name: string
}
iat: number
nbf: number
exp: number // iat + 10 days (864000s)
}
export const AccessTokenLifetimeSeconds = 10 * 24 * 3600 // exp - iat observed
Cross-references
- auth-and-link-session — the OAuth flow and refresh
- chat-submode-protocol — where the token is used
- attestation-flow — the integrity mechanism that validates the device