How can I verify a Google authentication API access token?
Asked Answered
K

13

199

How can I verify a Google authentication access token?

I need to somehow query Google and ask: Is [given access token] valid for the [[email protected]] Google account?

Short version

It's clear how an access token supplied through the Google Authentication Api :: OAuth Authentication for Web Applications can be used to then request data from a range of Google services. It is not clear how to check if a given access token is valid for a given Google account. I'd like to know how.

Long version

I'm developing an API that uses token-based authentication. A token will be returned upon provision of a valid username+password or upon provision of a third-party token from any one of N verifiable services.

One of the third-party services will be Google, allowing a user to authenticate against my service using their Google account. This will later be extended to include Yahoo accounts, trusted OpenID providers and so on.

Schematic example of Google-based access:

alt text

The 'API' entity is under my full control. The 'public interface' entity is any web- or desktop-based app. Some public interfaces are under my control, others will not be and others still I may never even know about.

Therefore I cannot trust the token supplied to the API in step 3. This will be supplied along with the corresponding Google account email address.

I need to somehow query Google and ask: Is this access token valid for [email protected]?

In this case, [email protected] is the Google account unique identifier - the email address someone uses to log in to their Google account. This cannot be assumed to be a Gmail address - someone can have a Google account without having a Gmail account.

The Google documentation clearly states how, with an access token, data can be retrieved from a number of Google services. Nothing seems to state how you can check if a given access token is valid in the first place.

Update The token is valid for N Google services. I can't try a token against a Google service as means of verifying it as I won't know which subset of all Google's services a given user actually uses.

Furthermore, I'll never be using the Google authentication access token to access any Google services, merely as a means of verifying a supposed Google user actually is who they say they are. If there is another way of doing this I'm happy to try.

Karlmarxstadt answered 11/12, 2008 at 14:11 Comment(4)
What specific auth service is this question about (OAuth, AuthSub, Installed Apps, ...)? Please provide a more detailed link.Inadvertence
@Martin v. Löwis: The 'OAuth Authentication for Web Applications' service - I've updated the start of the question to reflect this. Thanks for pointing this out!Karlmarxstadt
interesting article about google key verification might give more insight groups.google.com/group/Google-Maps-API/msg/f9e3c5ad3cbda4d7Obtain
FYI: the image URL is 404 even without the https.Oates
C
200

For user check, just post get the access token as accessToken and post it and get the response

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=accessToken

you can try in address bar in browsers too, use httppost and response in java also

response will be like

{
     "issued_to": "xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
     "audience": "xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
     "user_id": "xxxxxxxxxxxxxxxxxxxxxxx",
     "scope": "https://www.googleapis.com/auth/userinfo.profile https://gdata.youtube.com",
     "expires_in": 3340,
     "access_type": "offline"
    }

The scope is the given permission of the accessToken. you can check the scope ids in this link

Update: New API post as below

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

Response will be as

 {
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "[email protected]",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

For more info, https://developers.google.com/identity/sign-in/android/backend-auth

Cumulostratus answered 9/7, 2014 at 6:1 Comment(4)
There's a newer version for google's oauth2 - v3. See example here: developers.google.com/identity/sign-in/android/backend-authTrochee
-1 "It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors." developers.google.com/identity/sign-in/ios/… Remco's answer is the correct oneMagill
With the updated API, can I retrieve the user's google id?Barstow
"Calling the tokeninfo endpoint An easy way to validate an ID token signature for debugging is to use the tokeninfo endpoint. Calling this endpoint involves an additional network request that does most of the validation for you while you test proper validation and payload extraction in your own code. It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors." developers.google.com/identity/sign-in/android/backend-authArrio
A
118

Ok, most answers are valid but not quite right. The idea of JWT is that you can validate the token without the need to contact the issuer everytime. You must check the id and verify the signature of the token with the known public key of the certificate google used to sign the token.

See the next post why and how to do this.

http://ncona.com/2015/02/consuming-a-google-id-token-from-a-server/

Ananthous answered 2/8, 2016 at 11:20 Comment(6)
More upvotes please! The idea of JWT is that you can validate the token without the need to contact the issuer everytime.Faulty
yes! ppl are ddos-ing google if they just call google for token infoJablon
You can't do this with Google access tokens because they are not JWTs. Check #48624156Determination
@Determination Thanks for the insight. The id part is actually a verifiable jwt. Point still stands. Offline verification is the main idea here.Ananthous
Thank you! The documentation states "It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors." developers.google.com/identity/sign-in/web/…Pallas
@Ananthous Do you have any pointer about this "id part" of the access token and how to verify it offline? Could not find anything about it out there.Inhuman
L
46

you can verify a Google authentication access token by using this endpoint:

https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=<access_token>

This is Google V3 OAuth AccessToken validating endpoint, you can refer from google document below: (In OAUTH 2.0 ENDPOINTS Tab)

https://developers.google.com/identity/protocols/OAuth2UserAgent#validate-access-token

Liquefy answered 26/5, 2017 at 2:21 Comment(1)
For Backend documentation - documentation source is hereRollet
F
21

Use the below endpoint to get user info such as name, email, photo etc.

https://www.googleapis.com/oauth2/v3/userinfo?access_token=<access token>

Use the below endpoint to get token info, such as expiry time, token scope etc.

https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=<access token>
Florina answered 5/4, 2021 at 18:1 Comment(0)
G
18
function authenticate_google_OAuthtoken($user_id)
{
    $access_token   = google_get_user_token($user_id); // get existing token from DB
    $redirecturl    = $Google_Permissions->redirecturl;
    $client_id      = $Google_Permissions->client_id;
    $client_secret  = $Google_Permissions->client_secret;
    $redirect_uri   = $Google_Permissions->redirect_uri;
    $max_results    = $Google_Permissions->max_results;

    $url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$access_token;
    $response_contacts  =  curl_get_responce_contents($url);
    $response   =   (json_decode($response_contacts));

    if(isset($response->issued_to))
    {
        return true;
    }
    else if(isset($response->error))
    {
        return false;
    }
}
Gilemette answered 8/5, 2012 at 12:35 Comment(1)
This answer is almost still valid. Issued_to seems not to be set anymore however. developers.google.com/accounts/docs/…Acetaldehyde
D
13
  1. As per Google's documentation, you should use Google's AP Client Library that makes this (token verification, claim extraction etc.) much easier than writing your own custom code.

  2. From a performance perspective, the token should be parsed locally without making a call to Google again. Off-course Google's public key is needed and retrieval of that key is done using a caching strategy, implemented in the Google's client library from #1 above.

  3. FYI only. Google also uses a JWT token. See image below for reference.

enter image description here

Dragoman answered 17/10, 2020 at 2:36 Comment(1)
This answer deserves to be the accepted one. The proposed method is efficient both in terms of required code and consumed CPU/network resources for each verification. Compared to other answers recommending home-brew code, it's also less likely to introduce security vulnerabilities.Gonadotropin
S
11

Google oauth code flow response in addition to access_token also returns id_token that contains useful for validation info in encrypted form.

One thing that makes ID tokens useful is that fact that you can pass them around different components of your app. These components can use an ID token as a lightweight authentication mechanism authenticating the app and the user. But before you can use the information in the ID token or rely on it as an assertion that the user has authenticated, you must validate it.

Validation of an ID token requires several steps:

  • Verify that the ID token is a JWT which is properly signed with an appropriate Google public key.
  • Verify that the value of aud in the ID token is equal to your app’s client ID.
  • Verify that the value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com.
  • Verify that the expiry time (exp) of the ID token has not passed.
  • If you passed a hd parameter in the request, verify that the ID token has a hd claim that matches your Google Apps hosted domain.

https://developers.google.com/identity/protocols/OpenIDConnect#validatinganidtoken link has code samples for validation of ID tokens.

See also https://security.stackexchange.com/questions/37818/why-use-openid-connect-instead-of-plain-oauth.

Sorcerer answered 23/7, 2015 at 20:3 Comment(0)
M
1

Here's an example using Guzzle:

/**
 * @param string $accessToken JSON-encoded access token as returned by \Google_Client->getAccessToken() or raw access token
 * @return array|false False if token is invalid or array in the form
 * 
 * array (
 *   'issued_to' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
 *   'audience' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
 *   'scope' => 'https://www.googleapis.com/auth/calendar',
 *   'expires_in' => 3350,
 *   'access_type' => 'offline',
 * )
 */
public static function tokenInfo($accessToken) {
    if(!strlen($accessToken)) {
        return false;
    }

    if($accessToken[0] === '{') {
        $accessToken = json_decode($accessToken)->access_token;
    }

    $guzzle = new \GuzzleHttp\Client();

    try {
        $resp = $guzzle->get('https://www.googleapis.com/oauth2/v1/tokeninfo', [
            'query' => ['access_token' => $accessToken],
        ]);
    } catch(ClientException $ex) {
        return false;
    }

    return $resp->json();
}
Mease answered 13/7, 2015 at 3:9 Comment(0)
O
0

I need to somehow query Google and ask: Is this access token valid for [email protected]?

No. All you need is request standard login with Federated Login for Google Account Users from your API domain. And only after that you could compare "persistent user ID" with one you have from 'public interface'.

The value of realm is used on the Google Federated Login page to identify the requesting site to the user. It is also used to determine the value of the persistent user ID returned by Google.

So you need be from same domain as 'public interface'.

And do not forget that user needs to be sure that your API could be trusted ;) So Google will ask user if it allows you to check for his identity.

Orchardist answered 12/1, 2009 at 1:59 Comment(0)
T
0

Try making an OAuth-authenticated request using your token to https://www.google.com/accounts/AuthSubTokenInfo. This is only documented to work for AuthSub, but it works for OAuth too. It won't tell you which user the token is for, but it will tell you which services it's valid for, and the request will fail if the token is invalid or has been revoked.

Teodoor answered 26/2, 2009 at 6:51 Comment(0)
S
0

An arbitrary OAuth access token can't be used for authentication, because the meaning of the token is outside of the OAuth Core spec. It could be intended for a single use or narrow expiration window, or it could provide access which the user doesn't want to give. It's also opaque, and the OAuth consumer which obtained it might never have seen any type of user identifier.

An OAuth service provider and one or more consumers could easily use OAuth to provide a verifiable authentication token, and there are proposals and ideas to do this out there, but an arbitrary service provider speaking only OAuth Core can't provide this without other co-ordination with a consumer. The Google-specific AuthSubTokenInfo REST method, along with the user's identifier, is close, but it isn't suitable, either, since it could invalidate the token, or the token could be expired.

If your Google ID is an OpenId identifier, and your 'public interface' is either a web app or can call up the user's browser, then you should probably use Google's OpenID OP.

OpenID consists of just sending the user to the OP and getting a signed assertion back. The interaction is solely for the benefit of the RP. There is no long-lived token or other user-specific handle which could be used to indicate that a RP has successfully authenticated a user with an OP.

One way to verify a previous authentication against an OpenID identifier is to just perform authentication again, assuming the same user-agent is being used. The OP should be able to return a positive assertion without user interaction (by verifying a cookie or client cert, for example). The OP is free to require another user interaction, and probably will if the authentication request is coming from another domain (my OP gives me the option to re-authenticate this particular RP without interacting in the future). And in Google's case, the UI that the user went through to get the OAuth token might not use the same session identifier, so the user will have to re-authenticate. But in any case, you'll be able to assert the identity.

Speaking answered 28/8, 2009 at 23:45 Comment(1)
OpenID 2.0 was recenly deprecated and disabled by Google in favor of OAuth-based OpenID Connect that provides verifyable id tokens.Sorcerer
K
0

To elaborate on Vikrams answer, the currently recommended way is to use the google-auth-library to validate the token. Querying the google endpoint shouldn't be used in production.

For instance, for JavaScript:

npm install google-auth-library --save
const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client();
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 userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

Source: https://developers.google.com/identity/gsi/web/guides/verify-google-id-token

Karlsbad answered 10/2, 2024 at 22:53 Comment(0)
A
-2

Check below URL. It works well. Its official document from Google itself.

Using one of the Google API Client Libraries (e.g. Java, Node.js, PHP, Python) is the recommended way to validate Google ID tokens.

https://developers.google.com/identity/sign-in/android/backend-auth#using-a-google-api-client-library

Arrhythmia answered 27/2, 2022 at 6:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.