19

I am finding the way to validate ID token for Google sign-in for Android with a Go backend server project.

What is the equivalent function for validating ID tokens by using a Google API Client Library in Go?

From this page on Using a Google API Client Library section

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

There are Java and Python examples and there are links for verify ID tokens with the Google API Client Library for PHP, Node.js, and other languages. I checked for my target language; Go here

https://github.com/google/google-api-go-client/blob/master/GettingStarted.md

However, I found not equivalent function for validating token like in Java and Python example. Is there any function in Go for doing such thing?

I don't want to use token info endpoint

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

since it introduces possible latency and network error. I wish to use Google API Client Library. Please guide me where should I look into.

Zoe
  • 27,060
  • 21
  • 118
  • 148
ともこ
  • 775
  • 1
  • 5
  • 21

4 Answers4

33

It's very easy and has a one-liner solution. Just use the Official library:

go get google.golang.org/api/idtoken

and then write this code:

payload, err := idtoken.Validate(context.Background(), tokenString, audience)
if err != nil {
    panic(err)
}
fmt.Print(payload.Claims)

Then you will get this output:

map[
    aud:<Your web application client id>
    azp:<Your android application client id>
    email:<Authenticated user email> 
    email_verified:true
    exp:<expire at>
    family_name:<Authenticated user lastname>
    given_name:<Authenticated user firstname>
    iat:<issued at>
    iss: <accounts.google.com or https://accounts.google.com>
    locale:en
    name:<Authenticated User fullname>
    picture:<Authenticated User Photo URL>
    sub: <Google Account ID [Use this to identify a id uniquely]>
]

Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
princebillyGK
  • 2,917
  • 1
  • 26
  • 20
  • 4
    I believe this is the new correct answer. A little confusing that idtoken is a subpackage of oauth2 in other langs like Python, but in Go its a separate lib – Asad-ullah Khan Jun 18 '21 at 22:18
  • What is "audience"? – Brian Leishman Mar 30 '23 at 17:56
  • Here is github link in this code. > [google-api-go-client/idtoken/validate.go](https://github.com/googleapis/google-api-go-client/blob/main/idtoken/validate.go) – Jack Jun 02 '23 at 08:34
31

This is how I've done it using https://github.com/google/google-api-go-client library:

import (
    "google.golang.org/api/oauth2/v2"
    "net/http"
)

var httpClient = &http.Client{}

func verifyIdToken(idToken string) (*oauth2.Tokeninfo, error) {
    oauth2Service, err := oauth2.New(httpClient)
    tokenInfoCall := oauth2Service.Tokeninfo()
    tokenInfoCall.IdToken(idToken)
    tokenInfo, err := tokenInfoCall.Do()
    if err != nil {
        return nil, err
    }
    return tokenInfo, nil
}

oauth2.Tokeninfo object has info about the user. Note that this makes a call to https://www.googleapis.com/oauth2/v2/tokeninfo and I think that all Google API Client Libraries make this http call under the hood.

AlexCV
  • 496
  • 5
  • 4
  • It seems like we need to call oauth2/v3 not /v2 and if we still need to call to that url, how would it avoid the latency and network problem? – ともこ Apr 19 '16 at 14:05
  • google-api-go-client doesn't have oauth2/v3, but v2 works well. I don't know if you can avoid the http call. – AlexCV Apr 19 '16 at 15:34
  • `oauth2.New(httpClient)` seems like it's marked as deprecated in favour of `oauth2.NewService(ctx, ClientOption)` – Etienne Marais Aug 26 '20 at 11:55
  • 3
    [This issue](https://github.com/googleapis/google-api-go-client/issues/403#issuecomment-647806150) suggests that you should actually use the [idtoken](https://github.com/googleapis/google-api-go-client/tree/master/idtoken) package instead. – Gooz Mar 19 '21 at 00:48
8

Google's idToken is actually in JWT format, which is compact and self-contained JSON with signature.

See also: https://jwt.io/introduction/

google-auth-library-nodejs's OAuth2Client.prototype.verifyIdToken verify the idtoken using Google's public key and extract ClaimSet from the idtoken without calling the tokeninfo endpoint.

I just ported the verifyIdToken function from google-auth-library-nodejs, and created a library for this: https://github.com/futurenda/google-auth-id-token-verifier.

Usage:

import (
     "github.com/futurenda/google-auth-id-token-verifier"
)

v := googleAuthIDTokenVerifier.Verifier{}
aud := "xxxxxx-yyyyyyy.apps.googleusercontent.com"
err := v.VerifyIDToken(TOKEN, []string{
    aud,
})
if err == nil {
    claimSet, err := googleAuthIDTokenVerifier.Decode(TOKEN)
    // claimSet.Iss,claimSet.Email ... (See claimset.go)
}
Zeno Zeng
  • 301
  • 3
  • 7
8
import (
    "google.golang.org/api/idtoken"
)

var token string           // this comes from your web or mobile app maybe
const googleClientId = ""  // from credentials in the Google dev console

tokenValidator, err := idtoken.NewValidator(context.Background())
if err != nil {
    // handle error, stop execution
}

payload, err := tokenValidator.Validate(context.Background(), token, googleClientId)
if err != nil {
    // handle error, stop execution
}

email := payload.Claims["email"]
name  := payload.Claims["name"]
// and so on...

You may need to provide your Google credentials to your application: https://cloud.google.com/docs/authentication/production

Guy
  • 1,254
  • 17
  • 16
  • 3
    Before creating NewValidator, it expects that GOOGLE_APPLICATION_CREDENTIALS env variable is set to the json file downloaded from the console. Otherwise, idtoken.NewValidator fails as it expects some credentials. I can't get it to work with idtoken.Validate. I get this error: Get "https://www.googleapis.com/oauth2/v3/certs": private key should be a PEM or plain PKCS1 or PKCS8; parse error: asn1: syntax error: sequence truncated. Any idea? – Anton Jan 09 '21 at 17:25