Protect your API on Python

Extract the Bearer Token from request header

"""requires-auth.py
"""
def get_auth_token():
 auth = request.headers.get("Authorization", None)
 if not auth:
   raise Error({ code: 'auth.authorization_header_missing', status: 401 })
 contents = auth.split()
 if len(contents) < 2
   raise Error({code: 'auth.authorization_token_invalid_format', status: 401})
 elif contents[0] != 'Bearer'
   raise Error({code: 'auth.authorization_token_type_not_supported', status: 401})
 return contents[1]

Token validation

For demonstration, we use the Flask app and jose package to create the require_auth decorator to validate the token's signature, expiration status, and required claims.

Install jose as your dependency

pip install python-jose[rsa]

Retrieve Auth’s OIDC configurations

You will need a JWK public key set and the token issuer to verify the signature and source of the received JWS token. All the public Auth Authorization Configurations can be found at https://your-auth-domain/.well-known/openid-configuration.

e.g. Call https://nightly-accounts-api.complyment.com/.well-known/openid-configuration. And locate the following two fields in the response body:

{
 "jwks_uri": "https://nightly-accounts-api.complyment.com/.well-known/jwks.json",
 "issuer": "https://nightly-accounts-api.complyment.com"
}

Create the authorization validation decorator using the Auth’s configurations

"""requires-auth.py
"""
import json
from flask import request,  _request_ctx_stack
from six.moves.urllib.request import urlopen
from functools import wraps
from jose import jwt
def requires_auth(f):
 @wraps(f)
 def decorated(*args, **kwargs):
   token = get_token_auth_header()
   # jwks_uri endpoint retrieved from Auth
   jwks_uri = urlopen('https://nightly-accounts-api.complyment.com/.well-known/jwks.json')
   # issuer retrieved from Auth
   issuer = 'https://<your-auth-domain>'
   jwks = json.loads(jwks_uri.read())
   try:
     payload = jwt.decode(
       token,
       jwks,
       algorithms='RS256',
       audience='<your request listener resource indicator>',
       issue=issuer
       options={
         'verify_at_hash': False
       }
     )
   except Exception:
     # exception handler
     raise Error({code: 'invalid_token', status: 401})
     # Custom code to process payload
   _request_ctx_stack.top.user_id = payload.get('sub')
   return f(*args, **kwargs)
 return decorated

Apply decorator to your API

from flask import Flask
from flask_cors import cross_origin

APP = Flask(__name__)

@APP.route("/user/info")
@cross_origin(headers=["Content-Type", "Authorization"])
@requires_auth
def api:
 # Your API Logic

Last updated