{"record":{"id":"94d7f7609c833b78","repo":"slopus/happy","slug":"invalid-jwt-format","errorCode":null,"errorMessage":"Invalid JWT format","messagePattern":"Invalid JWT format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/commands/connect/authenticateCodex.ts","lineNumber":51,"sourceCode":"        .replace(/\\//g, '_');\n\n    return { verifier, challenge };\n}\n\n/**\n * Generate random state for OAuth security\n */\nfunction generateState(): string {\n    return randomBytes(16).toString('hex');\n}\n\n/**\n * Parse JWT token to extract payload\n */\nfunction parseJWT(token: string): any {\n    const parts = token.split('.');\n    if (parts.length !== 3) {\n        throw new Error('Invalid JWT format');\n    }\n\n    const payload = Buffer.from(parts[1], 'base64url').toString();\n    return JSON.parse(payload);\n}\n\n/**\n * Find an available port for the callback server\n */\nasync function findAvailablePort(): Promise<number> {\n    return new Promise((resolve) => {\n        const server = createServer();\n        server.listen(0, '127.0.0.1', () => {\n            const port = (server.address() as any).port;\n            server.close(() => resolve(port));\n        });\n    });\n}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/commands/connect/authenticateCodex.ts#L33-L69","documentation":"parseJWT splits the ID token on '.' and requires exactly three segments (header.payload.signature). If the token from the auth server is malformed, empty, or not a JWT, it throws immediately before attempting base64 decoding.","triggerScenarios":"data.id_token returned by the token endpoint is missing, undefined, an opaque token without dots, or otherwise not a three-part JWT; called from idTokenPayload after a successful token exchange.","commonSituations":"Auth provider changed response shape or omits id_token for some account types, a proxy strips the field, or an outdated CLI expects a claim the provider no longer issues.","solutions":["Log the raw id_token (length/parts) to confirm what the server returned","Check the token response actually includes id_token before calling parseJWT","Update the CLI / re-run auth so the provider issues a fresh valid ID token","Decode the payload defensively and skip account-ID extraction if absent"],"exampleFix":"// before\nconst idTokenPayload = parseJWT(data.id_token);\n// after\nif (typeof data.id_token !== 'string' || data.id_token.split('.').length !== 3) {\n    throw new Error('Server did not return a valid id_token');\n}\nconst idTokenPayload = parseJWT(data.id_token);","handlingStrategy":"validation","validationCode":"function isJwtShape(token) {\n  return typeof token === 'string' && token.split('.').length === 3;\n}\nif (!isJwtShape(data.id_token)) throw new Error('id_token missing or not a JWT');","typeGuard":"function isJwtToken(value: unknown): value is string {\n  return typeof value === 'string' && value.split('.').length === 3 && value.length > 0;\n}","tryCatchPattern":"try {\n  const payload = parseJWT(data.id_token);\n} catch (err) {\n  if (err.message === 'Invalid JWT format') {\n    // degrade gracefully: proceed without account-id extraction\n    console.warn('No valid id_token; skipping account ID parse');\n  } else throw err;\n}","preventionTips":["Validate the token response contains id_token before parsing","Log raw token shape when auth provider behavior changes","Keep CLI updated against provider API changes","Don't assume all account types receive an id_token"],"tags":["jwt","authentication","parsing"],"backgroundTag":"invalid-jwt-format","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}