Subje Native Google Login Token Exchange Fails with "invalid id_token: nonce required" in React Native

Subject: Native Google Login Token Exchange Fails with “invalid id_token: nonce required” in React Native

Description of the Issue
We are implementing a fully client-side native Google Login flow in our React Native application. The application obtains a Google ID Token via the native SDK, and then attempts to exchange it directly with Auth0’s token endpoint to retrieve Auth0 access, ID, and refresh tokens.

However, the token exchange request is rejected by Auth0 with the following error response:

json

{
“error”: “invalid_request”,
“error_description”: “invalid id_token: nonce required”
}

Hi @ansabvk122

The “nonce required” error is Auth0’s security engine blocking the exchange because it cannot verify that the Google token was generated specifically for this exact transaction. The error "invalid id_token: nonce required" occurs because Auth0 requires a nonce claim inside the Google ID Token when performing a native token exchange. This is a crucial security measure to prevent replay attacks. To fix this, you must generate a random nonce in your React Native app, pass it to the Google SDK during the native login, and then pass that same nonce to Auth0 during the token exchange.

When you use the standard web-based Universal Login, Auth0 handles generating a nonce , sending it to Google, and verifying it when Google returns the token.

When you use a Native SDK (fully client-side), you bypass Auth0 for the initial step. You are asking Google directly for an ID Token, and then handing that token to Auth0’s /oauth/token endpoint using the urn:ietf:params:oauth:grant-type:token-exchange grant type.

Because Auth0 was not involved in the initial request to Google, it has no way of knowing if the Google ID token you are providing is fresh, or if it is an old, stolen token being “replayed” by an attacker. To prove the token is fresh, Auth0 requires you to:

  1. Generate a random nonce string.
  2. Tell Google to embed that nonce directly into the signed payload of the Google ID Token.
  3. Pass that exact same nonce to Auth0 when you exchange the token.

SOLUTION:

  1. Before you trigger the native Google login, generate a secure random string in your React Native app. You can use libraries like react-native-get-random-values or standard crypto utilities.

  2. Update your Google Sign-In configuration to include the nonce parameter. The exact syntax depends on the React Native wrapper you are using (e.g., @react-native-google-signin/google-signin ).

// Example using @react-native-google-signin/google-signin
import { GoogleSignin } from '@react-native-google-signin/google-signin';

const myGeneratedNonce = generateSecureNonce(); 

GoogleSignin.configure({
  webClientId: 'YOUR_GOOGLE_WEB_CLIENT_ID', 
  offlineAccess: true, 
  nonce: myGeneratedNonce 
});

// Proceed with GoogleSignin.signIn()

  1. When you take the resulting Google ID Token and send it to Auth0’s /oauth/token endpoint, you must include the nonce parameter in your payload.
const response = await fetch('https://YOUR_TENANT.auth0.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
    client_id: 'YOUR_AUTH0_CLIENT_ID',
    subject_token: GOOGLE_ID_TOKEN,
    subject_token_type: 'urn:ietf:params:oauth:token-type:id_token',
    nonce: myGeneratedNonce
  })
});

If you have any other questions, let me know!

Kind Regards,
Nik