Note

This post is a thought. It's a short note that I make about someone else's content online. Learn more about the process thoughts

Here's my thought on 馃挱 First-class session support in FastAPI 路 Issue #754 路 tiangolo/fastapi


Here is a snippet provided by @tiangolo to store the users jwt inside of a session cookie in fatapi. This was written in feb 12, 2020 and admits that this is not a well documented part of fastapi.

It's already in place. More or less like the rest of the security tools. And it's compatible with the rest of the parts, integrated with OpenAPI (as possible), but probably most importantly, with dependencies.

It's just not properly documented yet. 馃槥

But still, it works 馃殌 e.g.

from fastapi import FastAPI, Form, HTTPException, Depends
from fastapi.security import APIKeyCookie
from starlette.responses import Response, HTMLResponse
from starlette import status
from jose import jwt


app = FastAPI()

cookie_sec = APIKeyCookie(name="session")

secret_key = "someactualsecret"

users = {"dmontagu": {"password": "secret1"}, "tiangolo": {"password": "secret2"}}


def get_current_user(session: str = Depends(cookie_sec)):
    try:
        payload = jwt.decode(session, secret_key)
        user = users[payload["sub"]]
        return user
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Invalid authentication"
        )


@app.get("/login")
def login_page():
    return HTMLResponse(
        """
        <form action="/login" method="post">
        Username: <input type="text" name="username" required>
        <br>
        Password: <input type="password" name="password" required>
        <input type="submit" value="Login">
        </form>
        """
    )


@app.post("/login")
def login(response: Response, username: str = Form(...), password: str = Form(...)):
    if username not in users:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Invalid user or password"
        )
    db_password = users[username]["password"]
    if not password == db_password:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Invalid user or password"
        )
    token = jwt.encode({"sub": username}, secret_key)
    response.set_cookie("session", token)
    return {"ok": True}


@app.get("/private")
def read_private(username: str = Depends(get_current_user)):
    return {"username": username, "private": "get some private data"}

This post was a thought by Waylon Walker see all my thoughts at https://waylonwalker.com/thoughts