“Building Secure and Robust Web APIs”

Unlocking the Power of OAuth2 with FastAPI middleware

Dykow
3 min readMar 6, 2023

Implementing Auth0 access token validation in Python FastApi is a great way to ensure that your API is secure and protected against unauthorized access. OAuth2 and Auth0 offer functional and security benefits, which include easy implementation and management of access control, multi-factor authentication, and user management. In this blog post I will try to show how to validate OAuth2 access tokens using FastApi Middleware and code from Auth0 blog post https://auth0.com/blog/build-and-secure-fastapi-server-with-auth0/.

The token verification process can be achieved using the PyJWT library, as shown in the code snippet provided in the blog post. The VerifyToken class is responsible for verifying the token, while the is_authenticated function checks whether the user is authenticated or not.

class VerifyToken():
"""Does all the token verification using PyJWT"""

def __init__(self, token):
self.token = token
self.config = set_up()
print(self.config)

# This gets the JWKS from a given URL and does processing so you can
# use any of the keys available
jwks_url = f'https://{self.config["DOMAIN"]}/.well-known/jwks.json'
self.jwks_client = jwt.PyJWKClient(jwks_url)

def verify(self, ):
# This gets the 'kid' from the passed token
try:
self.signing_key = self.jwks_client.get_signing_key_from_jwt(
self.token
).key
except jwt.exceptions.PyJWKClientError as error:
return {"status": "error", "msg": error.__str__()}
except jwt.exceptions.DecodeError as error:
return {"status": "error", "msg": error.__str__()}

try:
payload = jwt.decode(
self.token,
self.signing_key,
algorithms=self.config["ALGORITHMS"],
audience=self.config["API_AUDIENCE"],
issuer=self.config["ISSUER"],
)
except Exception as e:
return {"status": "error", "message": str(e)}

return payload


def is_authenticated(auth_result):
if auth_result.get("status"):
return False

return True

Using the AuthMiddleware class as a middleware in FastApi ensures that every request to the API is authenticated. The middleware extracts the token from the request header and verifies it using the VerifyToken class. If the authentication fails, the middleware returns a 403 Forbidden error. This way there is no need to do any other token validation later during request handling. If the request is passed further, it’s sure that it’s already authorized.

class AuthMiddleware:
def __init__(self):
pass

async def __call__(self, request: Request, call_next):
try:
token = request.headers.get("Authorization")
if not token:
raise InvalidSignatureError(403)
auth_result = VerifyToken(token.replace("Bearer ", "")).verify()
if is_authenticated(auth_result):
request.state.auth = auth_result
response = await call_next(request)
return response
else:
return JSONResponse(status_code=403, content="Forbidden")
except InvalidSignatureError as er:
return JSONResponse(status_code=403, content="Forbidden")

By adding decoded token to the request.state we can later access the data (such as user email or roles, which can be provided in the access token) in further request processing.

The final step is to append the middleware to the chain.

app = FastAPI()
auth_middleware = AuthMiddleware()
app.add_middleware(BaseHTTPMiddleware, dispatch=auth_middleware)

This is important to append it before other middleware, unless other it doesn’t require the request to be authenticated.

It is worth noting that there is another option for verifying a token in each controller request handler, as described in the original Auth0 blog post. However, in my implementation I used manual extraction of the token from the request header, as using the HTTPBearer class from the fastapi.security library wasn’t successful. There is also a potential for using https://fastapi-auth-middleware.code-specialist.com/ and/or request.auth field, but I haven’t tried that out.

--

--

Dykow
0 Followers

Systems Engineer, passionate about problem-solving & validating industry standards in software development, systems architecture & cybersecurity