Skip to main content

Guide: Python

Step 1: Extract the Bearer Token from request header

A authorized request should contain an Authorization header with Bearer <access_token> as its content. Extract the Authorization Token from the 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]

Step 2: 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 python-jose as your dependency

Pick the cryptography your are using in Logto. (ecdsa by default)

pip install python-jose[ecdsa]

Retrieve Logto'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 latest public Logto Authorization Configurations can be found at https://<your-logto-domain>/oidc/.well-known/openid-configuration.

e.g. Call https://tenant-id.logto.app/oidc/.well-known/openid-configuration. And locate the following two fields in the response body:

{
"jwks_uri": "https://tenant-id.logto.app/oidc/jwks",
"issuer": "https://tenant-id.logto.app/oidc"
}

Create the authorization validation decorator

warning

If you use Role-based access control, scope validation is also required.

"""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 Logto
jwks_uri = urlopen('https://<your-logto-domain>/oidc/jwks')

# issuer retrieved from Logto
issuer = 'https://<your-logto-domain>/oidc'

jwks = json.loads(jwks_uri.read())

try:
payload = jwt.decode(
token,
jwks,
# The jwt encode algorithm retrieved along with jwks. ES384 by default
algorithms=jwt.get_unverified_header(token).get('alg'),
# The API's registered resource indicator in Logto
audience='<your request listener resource indicator>',
issuer=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