pythonfastapiauth0authlib

Should I call Authlib's parse_id_token on every request?


I'm following Auth0's guide to adding login to a Python application and implementing it in my FastAPI application.

I've successfully completed every step of the guide and my application is working as expected. I am able to login and a token is placed in my session.

One thing I'm failing to grasp is: how does this token get validated in subsequent requests?

The example in guide shows a snippet that places the session in the rendered template:

@app.route("/")
def home():
    return render_template("home.html", session=session.get('user'), pretty=json.dumps(session.get('user'), indent=4))

And the template checks the existence of the token:

{% if session %}
    <h1>Welcome {{session.userinfo.name}}!</h1>
    <p><a href="/logout">Logout</a></p>
{% else %}
    <h1>Welcome Guest</h1>
    <p><a href="/login">Login</a></p>
{% endif %}

But surely just testing for the existence of the token in the session is not enough, right?

After digging around in Authlib's code I've found the method parse_id_token and so I've added middleware that calls it in every request to the webapp.

@app.middleware("http")
async def authenticate_request(request: Request, call_next):
    subject = request.session.get("subject")
    userinfo = await oauth.auth0.parse_id_token(get, nonce=get['userinfo']['nonce'])
    ...
    return await call_next(request)

Is this the correct way to validate all requests after the user has successfully logged in?


Solution

  • After your clarification, I would say that it all depends on the level of security you would like to provide and need and which tradeoffs in terms of performance (resources consumed) you are fine with.

    Checking every single request surely requires time to check and resources to decrypt the token (it isn't really encrypted, though it may be, but it is encoded so, I use the term decrypt to mean it in the broad sense).

    Fastapi exposes an HTTP api, which you seem to use. So, at every request, Fastapi does not know whether the user is the same, if the token expired or else, since the HTTP protocol itself is stateless. Thus, it may be another user at every request.

    TL;DR

    It is good practice that you check at every single request the provided token, otherwise someone without the correct token (which can be expired, wrong, missing, etc.) can access the requested resource. If exceptions are not handled well then the potential hacker may cause downtime, or worse, errors that crash your application.

    This will impact performances, but increase security. As mentioned above, it all depends on the level of security you need. Though, in my opinion, if you need a login, then there is a reason for checking at every request the user.

    A minor note

    That being said, regardless from your final choice, from a framework perspective, I would put the verification part in a Dependency for the set of routes that you want to protect instead of the middleware. See https://fastapi.tiangolo.com/tutorial/dependencies/ for further information regarding the Dependency system of Fastapi.