Home > OS >  Why is the Google OAuth 2.0 flow not returning an id_token when exchanged with the authorization cod
Why is the Google OAuth 2.0 flow not returning an id_token when exchanged with the authorization cod

Time:01-16

There's a clear diagram of the how this process works in Google's OAuth 2.0 docs. I've implemented the diagram as expected. My app hasn't been verified by Google yet, so the OAuth consent screen shows a warning and only allows whitelisted emails to be used in the OAuth process (until the app is verified). Using my email addresses, the code works perfectly. As soon as I started using some friends' emails for testing (all of which were whitelisted in the Google Developer Console), I'm not receiving the id_token. Interestingly, I'm not seeing any errors. Exchanging the code, I'm still receiving the access_token and refresh_token but not the id_token.

I don't think it's a problem with my code since I receive the id_token when using my personal email accounts, but here's my code anyways.

class GoogleOauthService implements GoogleOauth {
  #client;

  constructor() {
    this.#client = new google.auth.OAuth2(
      process.env.GOOGLE_CLIENT_ID,
      process.env.GOOGLE_CLIENT_SECRET,
      process.env.GOOGLE_REDIRECT_URL
    );
  }

  async getTokens(
    params: GoogleOauth.GetTokensParams
  ): GoogleOauth.GetTokensResult {
    const { tokens } = await this.#client.getToken(params.code);

    return {
      accessToken: tokens.access_token,
      refreshToken: tokens.refresh_token,
      scope: tokens.scope,
      tokenType: tokens.token_type,
      idToken: tokens.id_token,
      expiryDate: tokens.expiry_date,
    };
  }
}

I'm not receiving any errors from the call. tokens results in the following:

{
  access_token: 'secret access token',
  refresh_token: 'secret refresh token',
  scope: 'https://www.googleapis.com/auth/calendar',
  token_type: 'Bearer',
  expiry_date: 1673742003175
}

If anyone has any idea why Google isn't giving the id_token for some emails, I'd appreciate the insight.

CodePudding user response:

I'm now able to retrieve the id_token for accounts that I was previously unable to. The change I made was including the following in my OAuth 2.0 scopes

[
  'https://www.googleapis.com/auth/userinfo.profile',
  'https://www.googleapis.com/auth/userinfo.email',
];

Once these two scopes were included, the id_token appeared.

CodePudding user response:

The issue you were having was related to your scope of authorization you are not requesting the proper ones.

Here is a little background information on why you needed to change your scope.

Oauth2 is used for authorization, so if you want to request permission from a user to access their private user data.

I can see that you are requesting the scope of https://www.googleapis.com/auth/calendar You are using Oauth2 to request permission of a user to access their google calendar data this is Oauth2. The response will be an access token granting you access to their google calendar data and a refresh token. This is what Oauth2 responds with

{
  access_token: 'secret access token',
  refresh_token: 'secret refresh token',
  scope: 'https://www.googleapis.com/auth/calendar',
  token_type: 'Bearer',
  expiry_date: 1673742003175
}

Then we have Sign-in or authentication or Open Id connect which was actually built on top of Oauth2. Open Id connect allows you to verify that the user behind the machine is in fact the owner of the account. This is authencation not authorization. We are authenticating or signing in a user. Open Id connect returns an access token and a refresh token and an id token.

{
  "access_token": "[redacted]", 
  "id_token": "[redacted]", 
  "expires_in": 3599, 
  "token_type": "Bearer", 
  "scope": "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile", 
  "refresh_token": "[redacted]"
}

To use open id connect you need to use the profile, openid, and/ or email scopes. Then you will get back an access token granting you access to use profile information as well as the refrshtoken, and also an id token.

The id token is the key part of open id connect it gives you information on the user itself if you take it over to jwt.io you can decrypt the jwt.

{
  "iss": "https://accounts.google.com",
  "azp": "407408718192.apps.googleusercontent.com",
  "aud": "407408718192.apps.googleusercontent.com",
  "sub": "[MyInternalGoogleId]",
  "email": "[MyEmailAddress]",
  "email_verified": true,
  "at_hash": "Je-vk1k8MRaqK0gw3yXj7g",
  "name": "Linda Lawton",
  "picture": "https://lh3.googleusercontent.com/a/AEdFTp46WTOIbHj5Nl1VJRFf4Izj9YrX61i75F16H1qSA1Q=s96-c",
  "given_name": "Linda",
  "family_name": "Lawton",
  "locale": "en",
  "iat": 1673784532,
  "exp": 1673788132
}

The Id token allows you to verify after a user has been authenticated that they are in fact the owner of the account and just signed in.

as opposed to authorization which will only give you an access token with no guarantee that the one sending the access token was the user who owns the account, it could be an automated server app which has been granted authorization to access the users data.

  • Related