{"record":{"id":"78c08bf6f9eb1f8f","repo":"mastra-ai/mastra","slug":"invalid-google-id-token-nonce","errorCode":null,"errorMessage":"Invalid Google ID token nonce","messagePattern":"Invalid Google ID token nonce","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"auth/google/src/auth-provider.ts","lineNumber":360,"sourceCode":"    return [...this.allowedDomains];\n  }\n\n  getHostedDomain(): string | undefined {\n    return this.hostedDomain;\n  }\n\n  getClientId(): string {\n    return this.clientId;\n  }\n\n  private async verifyIdToken(token: string, nonce?: string): Promise<GoogleUser> {\n    const { payload } = await jwtVerify(token, this.jwks, {\n      issuer: GOOGLE_ISSUERS,\n      audience: this.clientId,\n    });\n\n    if (nonce && payload.nonce !== nonce) {\n      throw new Error('Invalid Google ID token nonce');\n    }\n\n    if (hasExpired(payload)) {\n      throw new Error('Google ID token has expired');\n    }\n\n    const user = mapGoogleClaimsToUser(payload);\n    if (!user.googleId) {\n      throw new Error('Google ID token is missing subject');\n    }\n\n    if (!this.isHostedDomainAllowed(user.hostedDomain)) {\n      throw new Error('Google user is not in an allowed hosted domain');\n    }\n\n    return user;\n  }\n","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/auth/google/src/auth-provider.ts#L342-L378","documentation":"verifyIdToken validates a Google-issued ID token (signature via JWKS, issuer, audience) and, when a nonce was supplied, compares it to the nonce claim embedded in the token. A mismatch means the token was not issued in response to the authentication request that carried this nonce, breaking replay protection, so the library rejects the token.","triggerScenarios":"Calling verifyIdToken(token, nonce) where payload.nonce differs from the provided nonce — e.g. the nonce came from a different/older login attempt, the state token's nonce was regenerated between the authorize redirect and callback, or two parallel login flows used different nonces.","commonSituations":"Replaying a recorded ID token in tests; verifying a token obtained from a refresh or a different browser tab; mixing state tokens across login attempts; nonce not persisted per-session so the callback verifies against the wrong value.","solutions":["Pass the exact nonce that was embedded in the state token for this login attempt (as returned by verifyStateToken / stored in the session).","Restart the login flow (new getLoginUrl) if the original attempt's nonce is unknown; never reuse nonces across attempts.","In tests, use the same nonce when minting the token and verifying it (e.g. deterministic test nonce).","Ensure session storage correctly persists the nonce between the authorize redirect and the callback."],"exampleFix":"// before (nonce regenerated before callback)\nconst nonce = crypto.randomUUID();\nconst user = await provider.verifyIdToken(token, nonce);\n\n// after (use nonce bound to this login's state)\nconst { nonce } = await provider.verifyStateToken(state);\nconst user = await provider.verifyIdToken(token, nonce);","handlingStrategy":"validation","validationCode":"const { nonce } = await provider.verifyStateToken(state);\nif (!nonce) throw new Error('Missing nonce for this login attempt');\nawait provider.verifyIdToken(token, nonce);","typeGuard":null,"tryCatchPattern":"try {\n  const user = await provider.verifyIdToken(token, expectedNonce);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Invalid Google ID token nonce') {\n    // possible replay/crossed login flows: reject and restart the OAuth flow\n    return res.redirect('/login');\n  }\n  throw err;\n}","preventionTips":["Persist the nonce from the state token in the user's session and verify against exactly that value.","Never regenerate the nonce between the authorize redirect and the callback.","Scope the nonce per login attempt; do not share it across tabs or parallel flows.","In tests, use a fixed nonce for both token minting and verification."],"tags":["oauth","openid-connect","nonce","security","token-validation"],"backgroundTag":"jwt-nonce-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}