Search code examples
google-cloud-platformgoogle-oauthpyjwt

Invalid JWT with pyjwt for Google Server to Server Applications


After failing to authenticate for Google Server to Server Applications using Python Oauthlib, I am now trying to generate directly the jwt with pyjwt then test it with curl as stated in Google documentation, but it does not work either since I now receive: Invalid JWT: Token must be a short-lived token and in a reasonable timeframe.

The code in Python 3 after installing pyjwt:

>>> from datetime import datetime, timedelta

>>> import json
>>> import jwt

>>> json_file = json.load(open("google-project-credentials.json"))
>>> dt_now = datetime.datetime.utcnow()
>>> payload = { 'iss' : json_file['client_email'], 'scope' : 'https://www.googleapis.com/auth/tasks', 'aud' : 'https://www.googleapis.com/oauth2/v4/token', 'exp' : int((dt_now + datetime.timedelta(hours=1)).timestamp()), 'iat': int(dt_now.timestamp()) }
>>> jwt.encode(payload, json_file['private_key'], algorithm='RS256')
b'PYJWT_RESULT_HERE'

Then, as stated in Google documentation, I run curl in bash and paste the previous result:

$ curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=PYJWT_RESULT_HERE' https://www.googleapis.com/oauth2/v4/token

Then I receive the following error:

{
  "error": "invalid_grant",
  "error_description": "Invalid JWT: Token must be a short-lived token and in a reasonable timeframe"
}

What am I doing wrong?

Thanks!


Solution

  • Actually, as stated in the error message, the problem was in the epoch that was incorrectly generated (I don't completely understand why yet):

    >>> from datetime import datetime
    >>> from calendar import timegm
    >>> import json
    >>> import jwt
    
    >>> json_file = json.load(open("google-project-credentials.json"))
    >>> payload = { 'iss' : json_file['client_email'], 'scope' : 'https://www.googleapis.com/auth/tasks', 'aud' : 'https://www.googleapis.com/oauth2/v4/token', 'exp' : timegm(datetime.utcnow().utctimetuple()) + 600, 'iat' : timegm(datetime.utcnow().utctimetuple()) }
    >>> jwt.encode(payload, json_file['private_key'], algorithm='RS256')
    b'PYJWT_RESULT_HERE'
    

    Then in a Bash console:

    $ curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=PYJWT_RESULT_HERE' https://www.googleapis.com/oauth2/v4/token
    {
      "access_token": "GOOGLE_ACCESS_TOKEN_YEAH",
       "token_type": "Bearer",
       "expires_in": 3600
    }
    

    I was actually surprised not to receive more help on that matter since I thought Google would be involved ;-( On open-source project, the support is actually better!