mastra-ai/mastra · error
Google ID token is missing subject
Error message
Google ID token is missing subject
What it means
mapGoogleClaimsToUser maps the JWT payload to a user; the googleId field comes from the token's sub (subject) claim. If googleId is missing, the token has no subject and cannot identify a user, so verifyIdToken throws. A Google ID token without a sub claim is not a valid identity assertion.
Source
Thrown at auth/google/src/auth-provider.ts:369
}
private async verifyIdToken(token: string, nonce?: string): Promise<GoogleUser> {
const { payload } = await jwtVerify(token, this.jwks, {
issuer: GOOGLE_ISSUERS,
audience: this.clientId,
});
if (nonce && payload.nonce !== nonce) {
throw new Error('Invalid Google ID token nonce');
}
if (hasExpired(payload)) {
throw new Error('Google ID token has expired');
}
const user = mapGoogleClaimsToUser(payload);
if (!user.googleId) {
throw new Error('Google ID token is missing subject');
}
if (!this.isHostedDomainAllowed(user.hostedDomain)) {
throw new Error('Google user is not in an allowed hosted domain');
}
return user;
}
private isHostedDomainAllowed(hostedDomain: string | undefined): boolean {
if (this.allowedDomains.length === 0) return true;
const domain = normalizeDomain(hostedDomain);
if (!domain) return false;
return this.allowedDomains.includes(domain);
}
private extractBearerToken(request: Request): string | null {
const authHeader = request.headers.get('Authorization');View on GitHub (pinned to 75dd419e61)
Solutions
- Use a genuine Google-issued ID token from a real OAuth code exchange.
- In tests, include sub in the mock token payload when minting tokens.
- Ensure your issuer configuration points only at Google's issuer URLs so foreign tokens can't reach this code path.
- Log the decoded payload (without secrets) to confirm which claims the offending token actually carries.
Example fix
// before (test mock without subject)
const payload = { aud: clientId, iss: 'https://accounts.google.com' };
// after
const payload = { aud: clientId, iss: 'https://accounts.google.com', sub: 'user-123', exp: ... }; Defensive patterns
Strategy: validation
Validate before calling
const { payload } = decodeJwt(token);
if (typeof payload.sub !== 'string' || payload.sub.length === 0) {
throw new Error('Token has no subject claim; cannot identify user');
} Type guard
function hasSubject(p: object): p is { sub: string } {
return 'sub' in p && typeof (p as { sub?: unknown }).sub === 'string' && (p as { sub: string }).sub.length > 0;
} Try / catch
try {
const user = await provider.verifyIdToken(token, nonce);
} catch (err) {
if (err instanceof Error && err.message === 'Google ID token is missing subject') {
// token is not a valid identity assertion: reject and restart flow
return res.redirect('/login');
}
throw err;
} Prevention
- Only accept tokens from Google's real issuer endpoints; don't lower issuer checks.
- In tests, always include sub (and aud/iss/exp) in mocked token payloads.
- Never accept hand-crafted tokens in production code paths.
- Log claim keys (not values) when debugging unexpected claim shapes.
When it happens
Trigger: Calling verifyIdToken with a token whose payload lacks the sub claim (or maps to a user with a falsy googleId) — typically a malformed, hand-crafted, or non-Google token that nevertheless passes issuer/audience checks, or a misconfigured mock in tests.
Common situations: Testing with locally forged JWTs that omit sub; a stub/mock JWKS issuing claim sets copied incorrectly; tokens from a non-Google IdP pointed at the same issuer/audience configuration.
Related errors
- Invalid Google ID token nonce
- Google ID token has expired
- Invalid state token format
- Invalid state token format
- Invalid or tampered state token
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7431d5103eb62a40.
Report an issue: GitHub.