'How to redirect to login in FastApi

I am looking to get a simple login sequence on fastapi: following This tutorial

from fastapi import FastAPI, Depends, HTTPException
from starlette.config import Config
from starlette.requests import Request
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import HTMLResponse, RedirectResponse
from authlib.integrations.starlette_client import OAuth, OAuthError

app = FastAPI()

app.add_middleware(SessionMiddleware, secret_key="!secret")

config = Config(".env")
oauth = OAuth(config)

CONF_URL = "https://accounts.google.com/.well-known/openid-configuration"
oauth.register(
    name="google",
    server_metadata_url=CONF_URL,
    client_kwargs={"scope": "openid email profile"},
)

@app.get("/")
async def home(request: Request):
    user = request.session.get("user")
    if user is not None:
        email = user["email"]
        html = (
            f"<pre>Email: {email}</pre><br>"
            '<a href="/docs">documentation</a><br>'
            '<a href="/logout">logout</a>'
        )
        return HTMLResponse(html)
    return HTMLResponse('<a href="/login">login</a>')

@app.get("/login", tags=["authentication"])
async def login(request: Request):
    redirect_uri = request.url_for("auth")
    return await oauth.google.authorize_redirect(request, redirect_uri)


@app.get("/auth")
async def auth(request: Request):
    try:
        token = await oauth.google.authorize_access_token(request)
    except OAuthError as error:
        return HTMLResponse(f"<h1>{error.error}</h1>")
    user = token.get("userinfo")
    if user:
        request.session["user"] = dict(user)
    return RedirectResponse(url="/")

@app.get("/logout", tags=["authentication"])
async def logout(request: Request):
    request.session.pop("user", None)
    return RedirectResponse(url="/")


# Try to get the logged in user
async def get_user(request: Request) -> Optional[dict]:
    user = request.session.get("user")
    if user is not None:
        return user
    else:
        raise HTTPException(status_code=403, detail="Could not validate credentials.")
    return None

# Endpoint to protect
@app.get("/other_endpoint/")
async def other_endpoint_function(
    user: Optional[dict] = Depends(get_user), id: str
):
    # Chek if other is authenticated
    if user.is_authenticated:
        function()
    else:
        # First redirect to the login page
        RedirectResponse("login")
        # Once logged in re-run the initial request
        RedirectResponse(f"/other_endpoint/{id}")

I am looking to protect only the other_endpoint the homepage has a link to the login page.

  • check that the user is authenticated before running the function
    • If the user is authenticated, run function
    • If the user is not authenticated
      1. redirect to the login page
      2. re-run the function after authentication

So far, I have tried multiple implementations with RedirectResponse, but i ends up bypassing the authentication



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source