Search code examples
python-3.xcookiesoauth-2.0fastapi

FastAPI: Deleting cookies after logout not working


I have tried to implement OAuth2 Cookie based Authentication using FastAPI. On calling /auth/token endpoint, it perfectly sets a HttpOnly cookie as shown below:

@router.post("/auth/token", response_model=Token)
async def get_token(response: Response, form_data: OAuth2PasswordRequestForm = Depends()):
    user = await authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password")
    access_token_expires = timedelta(minutes=Config.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.email_id}, expires_delta=access_token_expires
    )
    response.set_cookie(key="access_token", value=access_token, httponly=True)
    return {"access_token": access_token, "token_type": "bearer"}

Similarly, It should delete that cookie immediately after calling /logout endpoint as below:

@router.get("/logout")
async def logout(request: Request, response: Response, current_user: User = Depends(get_current_active_user)):
    # Also tried following two comment lines
    # response.set_cookie(key="access_token", value="", max_age=1)
    # response.delete_cookie("access_token", domain="localhost")
    response.delete_cookie("access_token")
    return templates.TemplateResponse("login.html", {"request": request, "title": "Login", "current_user": AnonymousUser()})

Problem: After calling /logout endpoint it should delete the cookie which it does but when I again click on /login it is able to retrieve the same cookie with same auth token i.e. browser send the same cookie along with the auth token in the request.

Here is the debug state of response after deleting cookies. It has deleted cookie from response object which is good:

debugger state response object

Here is the debug state of request when I attempt to login AFTER LOGOUT. It is still able to retrieve that cookie from browser:

debugger state request object

Any help regarding how to delete the cookies properly so that it could not be found again after logging out ?


Solution

  • Problem is with the response /logout endpoint is returning.

    As shown below, the line response.delete_cookies(key="access_token") is able to delete the cookie successfully debug state of response object

    On creating TemplateResponse object while returning, it creates a new response copying the same cookies from the request and kind of shadow the change (delete cookies) that we have done. So swapping last two lines in the logout() function solves the problem:

    @router.get("/logout")
    async def logout(request: Request, response: Response, current_user: User = Depends(get_current_active_user)):
        # Also tried following two comment lines
        # response.set_cookie(key="access_token", value="", max_age=1)
        # response.delete_cookie("access_token", domain="localhost")
        response = templates.TemplateResponse("login.html", {"request": request, "title": "Login", "current_user": AnonymousUser()})
        response.delete_cookie("access_token")
        return response