Skip to content

Getting started

Install FastAPI Sessions

The first step is to make sure you have FastAPI installed, along with Uvicorn for testing your API. If this sounds unfamiliar to you, first check out the FastAPI tutorial

Assuming you have your environment ready, lets install the library using pip.

pip install fastapi-sessions

Basic Usage

To get up and running with FastAPI sessions there are three main components you will use.

  1. SessionFrontend Abstract Class - This class provides the interface for extracting the session IDs from the request whether it is a cookie, header, etc.
  2. SessionBackend Abstract Class - This class provides the interface for CRUD operations of your session data.
  3. SessionVerifier Abstract Class - This class is where you verify that the provided session ID is actually valid.

Now lets take a quick look at a quick API. More details on configurations and design choices will be covered later.


Session Data

Its as simple as creating a pydantic model. No catches!

from pydantic import BaseModel

class SessionData(BaseModel):
    username: str

Session Frontend

We will use the provided SessionCookie frontend. The cookie's value is the signed UUID that is used as a key to the session data on the backend. Take notice of the identifier parameter, it connects the frontend to its corresponding verifier.

from fastapi_sessions.frontends.implementations import SessionCookie, CookieParameters

cookie_params = CookieParameters()

# Uses UUID
cookie = SessionCookie(
    cookie_name="cookie",
    identifier="general_verifier",
    auto_error=True,
    secret_key="DONOTUSE",
    cookie_params=cookie_params,
)

Session Backend

We will use the simple InMemoryBackend[ID, Data]() right now. It stores session data in the server's memory. As SessionCookie utilizes UUID that is our ID type.

from uuid import UUID
from fastapi_sessions.backends.implementations import InMemoryBackend

backend = InMemoryBackend[UUID, SessionData]()

Session Verifier

With the data, frontend, and backend all set up we now need to write our verifier. We will keep it simple and just have it verify that the session exists in the backend. It is a little unseemly as it utilizes Python's abstract classes. Notice we inerit from SessionVerifier which does all the heavy lifting of reading from the backend and obtaining the session from the frontend. The identifier must match the corresponding frontend identifier.

from fastapi_sessions.session_verifier import SessionVerifier
from fastapi import HTTPException

class BasicVerifier(SessionVerifier[UUID, SessionData]):
    def __init__(
        self,
        *,
        identifier: str,
        auto_error: bool,
        backend: InMemoryBackend[UUID, SessionData],
        auth_http_exception: HTTPException,
    ):
        self._identifier = identifier
        self._auto_error = auto_error
        self._backend = backend
        self._auth_http_exception = auth_http_exception

    @property
    def identifier(self):
        return self._identifier

    @property
    def backend(self):
        return self._backend

    @property
    def auto_error(self):
        return self._auto_error

    @property
    def auth_http_exception(self):
        return self._auth_http_exception

    def verify_session(self, model: SessionData) -> bool:
        """If the session exists, it is valid"""
        return True


verifier = BasicVerifier(
    identifier="general_verifier",
    auto_error=True,
    backend=backend,
    auth_http_exception=HTTPException(status_code=403, detail="invalid session"),
)

Bringing it together

Now we utilize FastAPI's dependency injection system to protect your routes! Furthermore FastAPI Sessions is compatible with the OpenAPI specs so they will show up in your docs as authenticated routes.

Create Session Route

Lets start with a simple session creation endpoint. This is not a protected.

from uuid import uuid4
from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/create_session/{name}")
async def create_session(name: str, response: Response):

    session = uuid4()
    data = SessionData(username=name)

    await backend.create(session, data)
    cookie.attach_to_response(response, session)

    return f"created session for {name}"

Now that our user can create a session, lets verify who they are. Notice how we depend on both the cookie and the verifier. The frontend must always be before the verifier as FastAPI Sessions relies on some hackery. It is to enable frontends and backends to be mixed and matched while still taking advantage of dependency injection and autodocs. The cookie extracts the session id and then the verifier checks the validity of the session.

from fastapi import Depends

@app.get("/whoami", dependencies=[Depends(cookie)])
async def whoami(session_data: SessionData = Depends(verifier)):
    return session_data

To end a session (e.g. logout), just delete it from the backend. As we now require the session_id we move it to be a dependency that returns a value. Not all frontends have the option, but with cookies we can delete it in the response which we do.

@app.post("/delete_session")
async def del_session(response: Response, session_id: UUID = Depends(cookie)):
    await backend.delete(session_id)
    cookie.delete_from_response(response)
    return "deleted session"

Putting it all together

Now lets put it all back together to see our session based authentication app.

Warning

While FastAPI-Sessions makes creating session based authentication easy, there are security implications. Please read through all the docs, especially Sessions (forthcoming), and do your own research if you have not worked with cookies and sessions for authentication before.

from pydantic import BaseModel
from fastapi import HTTPException, FastAPI, Response, Depends
from uuid import UUID, uuid4

from fastapi_sessions.backends.implementations import InMemoryBackend
from fastapi_sessions.session_verifier import SessionVerifier
from fastapi_sessions.frontends.implementations import SessionCookie, CookieParameters


class SessionData(BaseModel):
    username: str


cookie_params = CookieParameters()

# Uses UUID
cookie = SessionCookie(
    cookie_name="cookie",
    identifier="general_verifier",
    auto_error=True,
    secret_key="DONOTUSE",
    cookie_params=cookie_params,
)
backend = InMemoryBackend[UUID, SessionData]()


class BasicVerifier(SessionVerifier[UUID, SessionData]):
    def __init__(
        self,
        *,
        identifier: str,
        auto_error: bool,
        backend: InMemoryBackend[UUID, SessionData],
        auth_http_exception: HTTPException,
    ):
        self._identifier = identifier
        self._auto_error = auto_error
        self._backend = backend
        self._auth_http_exception = auth_http_exception

    @property
    def identifier(self):
        return self._identifier

    @property
    def backend(self):
        return self._backend

    @property
    def auto_error(self):
        return self._auto_error

    @property
    def auth_http_exception(self):
        return self._auth_http_exception

    def verify_session(self, model: SessionData) -> bool:
        """If the session exists, it is valid"""
        return True


verifier = BasicVerifier(
    identifier="general_verifier",
    auto_error=True,
    backend=backend,
    auth_http_exception=HTTPException(status_code=403, detail="invalid session"),
)

app = FastAPI()


@app.post("/create_session/{name}")
async def create_session(name: str, response: Response):

    session = uuid4()
    data = SessionData(username=name)

    await backend.create(session, data)
    cookie.attach_to_response(response, session)

    return f"created session for {name}"


@app.get("/whoami", dependencies=[Depends(cookie)])
async def whoami(session_data: SessionData = Depends(verifier)):
    return session_data


@app.post("/delete_session")
async def del_session(response: Response, session_id: UUID = Depends(cookie)):
    await backend.delete(session_id)
    cookie.delete_from_response(response)
    return "deleted session"