Search code examples
gooauth-2.0openid

How do I manually verify the signature of a JWT using Google's public key?


I’m implementing Google login in a Go script and I’m stuck trying to verify the ID Token has been signed by Google.

Specifically I’m trying to do the first bullet point in here.

I’ve obtained the token and split it into its header, payload and signature. But I don’t know how to use Google’s public key to verify the signature.

I saw that generating signature involves a HMACSHA256 algorithm, but I don’t quite know what to do with the JWK or PEM keys that Google provides. I’m currently doing it manually due to certain restrictions.

Does anyone know how I can verify the signature please?


Solution

  • Looking at the php example on https://github.com/googleapis/google-api-php-client/blob/2fb6e702aca5d68203fa737f89f6f774022494c6/src/AccessToken/Verify.php#L90, it appears that Google API signs the tokens using RS256(RSA Signature with SHA-256).

    The following code should verify the signature and parse the token. There is no need to split the token in your code. jwt.RSACheck(token []byte, key *rsa.PublicKey) (*jwt.Claims, error) in the "github.com/pascaldekloe/jwt" package would do all the heavy lifting for you.

    keyLocation is the Google public key stored locally

    package main
    
    import "github.com/pascaldekloe/jwt"
    
    //jwtValidator verifies and parses the JWT Token
    func jwtValidator(token string, keyLocation string) (j *jwtToken, err error) {
        token := []byte(token)
    
        pubK, err := rsaPublicKey(keyLocation)
        if err != nil {
            return
        }
    
        // parses the token only if signature is valid
        claims, err := jwt.RSACheck(token, pubK)
        if err != nil {
            err = fmt.Errorf("token signature invalid %s", err)
            return
        }
        if !claims.Valid(time.Now()) {
            err = fmt.Errorf("token time constraints exceeded")
            return
        }
    
        j = &jwtToken{
            id:      claims.ID,
            issuer:  claims.Issuer,
            issued:  claims.Issued,
            subject: claims.Subject,
            expires: claims.Expires,
        }
    
        return
    }