Flask Snippets

Snippets are unofficial and unmaintained.

This is an archived view of user-submitted snippets. Despite being hosted on the Flask site, they are not official. No Flask maintainer has curated or checked the snippets for security, correctness, or design.

Verify a Google authentication token

Posted by SpaceCowboy on 2014-10-05 @ 21:35 and filed in Decorators

For my simple REST API, I needed to verify bearer tokens to get the email of the user. The token is retrieved by the client via an Android app, so I didn't need any of the login features offered in other solutions.

A requirement is 'httplib2', so do:

pip install httplib2

Then the code is very simple:

# put this in for example gauth.py
def validate_token(access_token):
    '''Verifies that an access-token is valid and
    meant for this app.

    Returns None on fail, and an e-mail on success'''
    h = Http()
    resp, cont = h.request("https://www.googleapis.com/oauth2/v2/userinfo",
                           headers={'Host': 'www.googleapis.com',
                                    'Authorization': access_token})

    if not resp['status'] == '200':
        return None

    try:
        data = json.loads(cont)
    except TypeError:
        # Running this in Python3
        # httplib2 returns byte objects
        data = json.loads(cont.decode())

    return data['email']

def authorized(fn):
    """Decorator that checks that requests
    contain an id-token in the request header.
    userid will be None if the
    authentication failed, and have an id otherwise.

    Usage:
    @app.route("/")
    @authorized
    def secured_root(userid=None):
        pass
    """

    def _wrap(*args, **kwargs):
        if 'Authorization' not in request.headers:
            # Unauthorized
            print("No token in header")
            abort(401)
            return None

        print("Checking token...")
        userid = validate_token(request.headers['Authorization'])
        if userid is None:
            print("Check returned FAIL!")
            # Unauthorized
            abort(401)
            return None

        return fn(userid=userid, *args, **kwargs)
    return _wrap

An example would be:

from gauth import authorized

@app.route('/')
@authorized
def root(self, userid):
      return "Hello {}".format(userid)

Any route decorated with @authorized has to have the keyword argument 'userid'.

This snippet by SpaceCowboy can be used freely for anything you like. Consider it public domain.