Protect your API on Python
note
Make sure to register your api resource in Logto Admin Console before continuing.
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 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://logto.dev/oidc/.well-known/openid-configuration
. And locate the following two fields in the response body:
{
"jwks_uri": "https://logto.dev/oidc/jwks",
"issuer": "https://logto.dev/oidc"
}
Create the authorization validation decoratorโ
"""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
note
For ๐ RBAC, scope validation is also required.
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