Alex
Alex

Reputation: 19104

Verify Id Token In Android Backend Call to Python

As explained here, I am trying to verify a token that is passed, by an Android app, to a server running python3.

I want to verify the passed token. The trouble is that I am running python3 on the server which is not supported by the google-api-python-client library. I found the following workaround, using the pyjwt and requests libraries, from this site:

import json
import jwt
import requests

GOOGLE_CERTS_URI = 'https://www.googleapis.com/oauth2/v1/certs'


class GoogleIdToken(object):
    def __init__(self):
        self._certs = {}
        self._token = {}

    def getCerts(self):
        cert = requests.get(GOOGLE_CERTS_URI)
        if cert.status_code == 200:
            return json.loads(cert.content)

    def isValid(self, token, audience, clientId=None):
        self._certs = self.getCerts()
        for key in self._certs:
            try:
                token = jwt.decode(token, key=self._certs[key], verify=False)
                if 'email' in token and 'aud' in token:
                    if token['aud'] == audience and (clientId == token['cid'] if clientId is not None else True):
                        self._token = token
                        return True
            except Exception, e:
                print("Error decoding: %s" % e.message)
        return False

My two questions are:

  1. Does anyone know of a different and/or better existing solution that works in python3?
  2. Is the solution above complete?

Upvotes: 4

Views: 1371

Answers (2)

simlmx
simlmx

Reputation: 1333

After a few hours of googling around and some trial and error, this is how I ended up doing it.

Dependencies

pip install cryptography PyJWT requests

Code

import jwt, requests
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend

GOOGLE_CERTS_URI = 'https://www.googleapis.com/oauth2/v1/certs'

def verify_id_token(id_token, audience):
    certs = requests.get(GOOGLE_CERTS_URI).json()

    for cert in certs.values():
        cert = str.encode(cert)
        cert_obj = load_pem_x509_certificate(cert, default_backend())
        pub_key = cert_obj.public_key()
        try:
            return jwt.decode(id_token, pub_key, algorithm='RS256',
                              audience=audience)
        except (jwt.exceptions.DecodeError,
                jwt.exceptions.ExpiredSignatureError) as e:
            pass

EDIT

I just realized Google provides an example in python for that, using their oauth2client library.

Upvotes: 2

skyjacks
skyjacks

Reputation: 1154

The Google API was recently ported to Python 3x and includes jwt verification. You can access it here.

As for your work around the only thing I'd highlight is the same point that Stefan made on the link you posted. That being the security vulnerability you're introducing as a result of having verify=False in your jwt decode call.

Upvotes: 0

Related Questions