Security: Google provider should verify nonce in verifyIdToken #2452

Closed
opened 2026-03-13 09:55:44 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @j-xzy on GitHub (Dec 4, 2025).

Is this suited for github?

  • Yes, this is suited for github

No response

Describe the solution you'd like

The Google OAuth provider's verifyIdToken method currently accepts a nonce parameter but does not validate it against the ID token claims. This creates a security vulnerability as it allows potential replay attacks and doesn't follow OpenID Connect best practices.

Current implementation (packages/core/src/social-providers/google.ts:122-146):

  async verifyIdToken(token, nonce) {
      // ... validation logic ...
      // nonce parameter is received but never used
  }

Proposed solution:

  1. Decode the JWT to extract the nonce claim
  2. Compare it with the provided nonce parameter
  3. Return false if they don't match

Implementation approach:

  async verifyIdToken(token, nonce) {
      if (options.disableIdTokenSignIn) {
          return false;
      }
      if (options.verifyIdToken) {
          return options.verifyIdToken(token, nonce);
      }

      const googlePublicKeyUrl =
  `https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`;
      const { data: tokenInfo } = await betterFetch<{
          aud: string;
          iss: string;
          email: string;
          email_verified: boolean;
          name: string;
          picture: string;
          sub: string;
          nonce?: string;  // Add nonce field
      }>(googlePublicKeyUrl);

      if (!tokenInfo) {
          return false;
      }

      // Verify nonce to prevent replay attacks
      if (nonce && tokenInfo.nonce !== nonce) {
          return false;
      }

      const isValid =
          tokenInfo.aud === options.clientId &&
          (tokenInfo.iss === "https://accounts.google.com" ||
              tokenInfo.iss === "accounts.google.com");
      return isValid;
  }

Why this matters:

  • Security: Prevents ID token replay attacks
  • OIDC Compliance: Aligns with OpenID Connect specification requirements
  • Consistency: The Apple provider (packages/core/src/social-providers/apple.ts:134-136) already
    implements nonce validation correctly
Originally created by @j-xzy on GitHub (Dec 4, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. _No response_ ### Describe the solution you'd like The Google OAuth provider's verifyIdToken method currently accepts a nonce parameter but does not validate it against the ID token claims. This creates a security vulnerability as it allows potential replay attacks and doesn't follow OpenID Connect best practices. Current implementation (packages/core/src/social-providers/google.ts:122-146): ``` async verifyIdToken(token, nonce) { // ... validation logic ... // nonce parameter is received but never used } ``` Proposed solution: 1. Decode the JWT to extract the nonce claim 2. Compare it with the provided nonce parameter 3. Return false if they don't match Implementation approach: ``` async verifyIdToken(token, nonce) { if (options.disableIdTokenSignIn) { return false; } if (options.verifyIdToken) { return options.verifyIdToken(token, nonce); } const googlePublicKeyUrl = `https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`; const { data: tokenInfo } = await betterFetch<{ aud: string; iss: string; email: string; email_verified: boolean; name: string; picture: string; sub: string; nonce?: string; // Add nonce field }>(googlePublicKeyUrl); if (!tokenInfo) { return false; } // Verify nonce to prevent replay attacks if (nonce && tokenInfo.nonce !== nonce) { return false; } const isValid = tokenInfo.aud === options.clientId && (tokenInfo.iss === "https://accounts.google.com" || tokenInfo.iss === "accounts.google.com"); return isValid; } ``` Why this matters: - Security: Prevents ID token replay attacks - OIDC Compliance: Aligns with OpenID Connect specification requirements - Consistency: The Apple provider (packages/core/src/social-providers/apple.ts:134-136) already implements nonce validation correctly
GiteaMirror added the security label 2026-03-13 09:55:44 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 4, 2025):

Hi there, thanks for raising this important security concern. To address this issue, you can update the Google provider's verifyIdToken method so that it decodes the token, extracts the nonce claim, and compares it against the provided nonce parameter. This will help prevent replay attacks and align with OIDC best practices, similar to what the Apple provider does [1]. One straightforward approach is to query the tokeninfo endpoint, validate the nonce from its response, and return false if there's a mismatch. Alternatively, you could migrate to using full JWT verification (using a library like jose), which would involve retrieving and caching Google’s public keys for more robust security [2]. How would you like to proceed on this – would a quick tokeninfo-based nonce check work for you, or are you leaning toward the full JWT verification approach? tag @better-auth-agent if you would like an answer from the Agent

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Dec 4, 2025): Hi there, thanks for raising this important security concern. To address this issue, you can update the Google provider's verifyIdToken method so that it decodes the token, extracts the nonce claim, and compares it against the provided nonce parameter. This will help prevent replay attacks and align with OIDC best practices, similar to what the Apple provider does [[1]](https://github.com/better-auth/better-auth/issues/1183). One straightforward approach is to query the tokeninfo endpoint, validate the nonce from its response, and return false if there's a mismatch. Alternatively, you could migrate to using full JWT verification (using a library like jose), which would involve retrieving and caching Google’s public keys for more robust security [[2]](https://github.com/better-auth/better-auth/issues/6446). How would you like to proceed on this – would a quick tokeninfo-based nonce check work for you, or are you leaning toward the full JWT verification approach? tag @better-auth-agent if you would like an answer from the Agent _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2452