slopus/happy · error

Invalid JWT format

Error message

Invalid JWT format

What it means

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.

Source

Thrown at packages/happy-cli/src/commands/connect/authenticateCodex.ts:51

        .replace(/\//g, '_');

    return { verifier, challenge };
}

/**
 * Generate random state for OAuth security
 */
function generateState(): string {
    return randomBytes(16).toString('hex');
}

/**
 * Parse JWT token to extract payload
 */
function parseJWT(token: string): any {
    const parts = token.split('.');
    if (parts.length !== 3) {
        throw new Error('Invalid JWT format');
    }

    const payload = Buffer.from(parts[1], 'base64url').toString();
    return JSON.parse(payload);
}

/**
 * Find an available port for the callback server
 */
async function findAvailablePort(): Promise<number> {
    return new Promise((resolve) => {
        const server = createServer();
        server.listen(0, '127.0.0.1', () => {
            const port = (server.address() as any).port;
            server.close(() => resolve(port));
        });
    });
}

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Log the raw id_token (length/parts) to confirm what the server returned
  2. Check the token response actually includes id_token before calling parseJWT
  3. Update the CLI / re-run auth so the provider issues a fresh valid ID token
  4. Decode the payload defensively and skip account-ID extraction if absent

Example fix

// before
const idTokenPayload = parseJWT(data.id_token);
// after
if (typeof data.id_token !== 'string' || data.id_token.split('.').length !== 3) {
    throw new Error('Server did not return a valid id_token');
}
const idTokenPayload = parseJWT(data.id_token);
Defensive patterns

Strategy: validation

Validate before calling

function isJwtShape(token) {
  return typeof token === 'string' && token.split('.').length === 3;
}
if (!isJwtShape(data.id_token)) throw new Error('id_token missing or not a JWT');

Type guard

function isJwtToken(value: unknown): value is string {
  return typeof value === 'string' && value.split('.').length === 3 && value.length > 0;
}

Try / catch

try {
  const payload = parseJWT(data.id_token);
} catch (err) {
  if (err.message === 'Invalid JWT format') {
    // degrade gracefully: proceed without account-id extraction
    console.warn('No valid id_token; skipping account ID parse');
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31). Data as JSON: /api/errors/94d7f7609c833b78. Report an issue: GitHub.