How does Auth0 work and how to protect our API endpoints


First, let’s clarify some terms involved in this process:

  • Audience: Typically a URI or a unique identifier for the API or resource server the client aims to access. It’s utilized to ensure that an access token is presented to the correct resource server, which verifies the audience value matches its identifier.
  • Client ID and Client Secret: Credentials provided by the authorization server (e.g., Auth0) to the client. These are used by the client to authenticate itself to the authorization server when requesting a token.
  • Access Token: The token presented by the client to the resource server (API) as proof of authorization to access resources on behalf of the user or itself, in machine-to-machine communication.

How to Set Up Auth0 to Secure a FastAPI Application

On the Auth0 Provider Site

To protect our resource (the API), the following steps are necessary:

  1. Resource Setup:
    • Set up a resource with a unique name, which could be your API name or project name. This distinct name allows the Auth0 provider to differentiate among the various resources that need protection. In Auth0 context, this resource is also referred to as the audience.
  2. Client Configuration:
    • For every potential user that will call your API (referred to as a client), create a client in Auth0 that will have access to the resource you’ve set up. This includes obtaining a Client ID and a Client Secret.

Using the Client ID and Secret in Your App

With these credentials (Client ID and secrets):

  1. When clients wish to call your API, they first request a JWT token (bearer token) from the Auth0 domain by providing the Client ID, Client Secret, and the audience (resource name).

Here’s an example in Python:

import requests

# Replace these with your actual details
AUTH0_DOMAIN = 'YOUR_DOMAIN'
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
AUDIENCE = 'YOUR_AUDIENCE'

url = f"https://{AUTH0_DOMAIN}/oauth/token"

payload = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'audience': AUDIENCE,
'grant_type': 'client_credentials'
}

headers = {
'content-type': "application/json"
}

response = requests.post(url, json=payload, headers=headers)

if response.status_code == 200:
# Extract access token from response
access_token = response.json()['access_token']
print("Access Token:", access_token)
else:
print("Failed to retrieve access token")
print("Status Code:", response.status_code)
print("Response:", response.text)
  1. With this token, which typically has a limited lifetime of a few hours, the client can then authenticate and make calls to your API.

Validating the Access Token on the FastAPI Side

To validate incoming tokens, follow these steps:

  1. Fetch the public key from the Auth0 provider page and use the RSA256 algorithm to verify if the token from the user is valid.

Here’s how to validate tokens in Python:

pip install pyjwt[crypto] requests

import json
import requests
from jwt import decode, exceptions
from jwt.algorithms import RSAAlgorithm

AUTH0_DOMAIN = 'YOUR_AUTH0_DOMAIN'

def get_jwks():
jwks_url = f'https://{AUTH0_DOMAIN}/.well-known/jwks.json'
try:
jwks_resp = requests.get(jwks_url)
jwks = jwks_resp.json()
return jwks
except Exception as e:
print(f"Error fetching JWKS: {e}")
return None

def get_public_key(token):
jwks = get_jwks()
if not jwks:
return None

unverified_header = decode(token, options={"verify_signature": False}, algorithms=["RS256"])
if not unverified_header:
return None

rsa_key = {}
for key in jwks["keys"]:
if key["kid"] == unverified_header['kid']:
rsa_key = {
"kty": key["kty"],
"kid": key["kid"],
"use": key["use"],
"n": key["n"],
"e": key["e"]
}
if rsa_key:
try:
public_key = RSAAlgorithm.from_jwk(json.dumps(rsa_key))
return public_key
except Exception as e:
print(f"Error constructing public key: {e}")
return None
return None

def validate_token(token, audience, issuer):
public_key = get_public_key(token)
if public_key is None:
return False

try:
payload = decode(token, public_key, algorithms=["RS256"], audience=audience, issuer=issuer)
return True # Token is valid
except exceptions.InvalidTokenError as e:
print(f"Invalid token: {e}")
return False # Token is invalid

# Example usage
token = "YOUR_JWT_TOKEN"
audience = "YOUR_AUDIENCE"
issuer = f"https://{AUTH0_DOMAIN}/"

if validate_token(token, audience, issuer):
print("Token is valid.")
else:
print("Token is invalid or verification failed.")

That concludes the setup to secure a FastAPI application with Auth0.

```
This guidance provides a structured approach for integrating Auth0 authentication into a FastAPI app, highlighting the necessary steps and providing code snippets for practical implementation.


Author: robot learner
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source robot learner !
  TOC