'Sign in with Google - What should I do with `nonce`?

What I'm doing now:

  1. Using the JavaScript API to render the button on my web page.
  2. When the Sign in with Google flow is complete, my client-side JavaScript callback is called.
  3. That callback sends the given .credentials string to my server.
  4. The backend server (Node.js) calls the google-auth-library library's OAuth2Client.verifyIdtoken method on the .credentials string, which returns the user's email address (among other things), which my server uses to verify the user and create a session.

Everything works, but I'm wondering if there are any security concerns I'm missing. In particular there's a nonce field. The docs (link) don't explain how to use it.

Note: I'm using "Sign in with Google" and not the deprecated "Google Sign-In".

Edit: I'm familiar with the concept of nonces and have used them when doing the OAuth 2 server-side flow myself. What I can't figure out is how the Sign in with Google SDK expects me to use its nonce parameter with the flow above, where I'm using both their client-side and server-side SDKs.



Solution 1:[1]

Nonces are used as a CSRF-prevention method. When you make a request to Google, you include a nonce, and when authentication is complete, Google will send the same nonce back. The magic in this method is that if the nonce does not match what you sent then you can ignore the response, because it was probably spoofed.

Read more about CSRF here: https://owasp.org/www-community/attacks/csrf

Nonces are usually crytographically secure random strings/bytes.

I use crypto-random-string as a base to generate nonces, but any package with this functionality should suffice.

Sometimes I store nonces with a TTL in Redis, but other times I store nonces with an ID attached to the request so I can later verify it.

I'm telling you this since it took a bit long for me to figure out this nonce stuff :P

Solution 2:[2]

Using the example from Google's website (https://developers.google.com/identity/one-tap/android/idtoken-auth), I added the code for the nonce:

const nonce = '...'; // Supplied by client in addition to token
const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const serverNonce = payload['nonce'];
  if (nonce != serverNonce) {
    // Return an error
  }

  const userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Werner Altewischer