Search code examples
pythonfastapi

Pass on value from dependencies in include_router to routes FastAPI


I was wondering if it was possible to pass the results from the dependencies kwarg in include_router to the router that is passed to it. What I want to do is decode a JWT from the x-token header of a request and pass the decoded payload to the books routes.

I know that I could just write authenticate_and_decode_JWT as a dependency of each of the routes in routers/book.py, but this would be quite repetitive for a large app.

main.py

from typing import Optional
from jose import jwt

from fastapi import FastAPI, Depends, Header, HTTPException, status
from jose.exceptions import JWTError

from routers import books


app = FastAPI()

def authenticate_and_decode_JWT(x_token: str = Header(None)):
    try:
        payload = jwt.decode(x_token.split(' ')[1], 'secret key', algorithms=['HS256'])
        return payload # pass decoded user information from here to books.router routes somehow
    except JWTError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)

app.include_router(
    books.router,
    prefix="/books",
    dependencies=[Depends(authenticate_and_decode_JWT)], 
)

@app.get("/")
def read_root():
    return {"Hello": "World"}

routers/books.py

from fastapi import APIRouter

router = APIRouter()

@router.get('/')
def get_book():
    # do stuff with decoded authenticated user data from JWT payload here
    pass

@router.post('/')
def create_book():
    # do stuff with decoded authenticated user data from JWT payload here
    pass

Solution

  • While the answer above about writing a middleware does work, if you don't want a middleware, you just want to use the include_router, then you can take the authenticate_and_decode_JWT method and extend it to write the JWT payload into the request object and then later have your routes read from that out from the request object.

    This way you only need to modify a few lines in your code for it to work:

    from fastapi import Request  # <== new import
    
    def authenticate_and_decode_JWT(x_token: str = Header(None), request: Request):   # <== request is a new param
        try:
            payload = jwt.decode(x_token.split(' ')[1], 'secret key', algorithms=['HS256'])
            request.token_payload = payload  # type: ignore   # <== store the token payload in request
            return payload
        except JWTError:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
    

    And then read from request:

    from fastapi import Request   # <== new import
    
    @router.get('/', request: Request)   # <== request is a new param
    def get_book():
        # do stuff with decoded authenticated user data from JWT payload here
        print(request.token_payload)   # <== access your token payload