# FastAPI MultiAuth

**Composable authentication sources for FastAPI.** You write the function that decides who a credential belongs to; the library extracts the credential, combines several schemes on one route, and declares all of it in OpenAPI.

No user model, no database coupling, no ready-made `/login` routes. Your store, your rules.

## Installation

```bash
uv add fastapi-multiauth
```

```bash
pip install fastapi-multiauth
```

Optional extras: `jwt` for [`JWTValidator`](<https://fastapi-multiauth.d3vyce.fr/guide/jwt-and-oauth2/index.md>), `oauth` for the [OAuth login helpers](<https://fastapi-multiauth.d3vyce.fr/guide/oauth-login/index.md>).

## A first route

One route that accepts either an API token or a browser session cookie:

```python
import os

from fastapi import FastAPI, Security

from fastapi_multiauth import (
    APIKeyCookieAuth,
    HTTPBearerAuth,
    MultiAuth,
    UnauthorizedError,
    hash_token,
)

SECRET_KEY = os.environ["SECRET_KEY"]
USERS = {"1": {"id": "1", "name": "alice"}}
TOKENS = {hash_token("user_alice-token"): "1"}


async def validate_token(token: str) -> dict:
    user_id = TOKENS.get(hash_token(token))
    if user_id is None:
        raise UnauthorizedError()
    return USERS[user_id]


async def validate_session(user_id: str) -> dict:
    if user_id not in USERS:
        raise UnauthorizedError()
    return USERS[user_id]


bearer = HTTPBearerAuth(validator=validate_token, prefix="user_")
session = APIKeyCookieAuth(
    name="__Host-session", validator=validate_session, secret_key=SECRET_KEY
)
auth = MultiAuth(bearer, session)

app = FastAPI()


@app.get("/me")
async def me(user: dict = Security(auth)):
    return user
```

- A **validator** is a function you write: it receives the credential and returns the user, or raises to refuse it.
- `HTTPBearerAuth(..., prefix="user_")` reads `Authorization: Bearer user_...` tokens.
- `APIKeyCookieAuth` reads a signed cookie; your validator only sees the value once the signature checks out. `SECRET_KEY` must hold at least 32 random bytes, e.g. from `secrets.token_urlsafe(32)`.
- `MultiAuth` uses whichever one the request carries, and both appear in `/docs`.

## What you get

- **Every standard scheme**

  ---

  Bearer tokens, signed cookies, API keys, HTTP Basic, OAuth 2.0 and OpenID Connect.
- **Several schemes, one route**

  ---

  `MultiAuth` tries sources in order and documents all of them.
- **Step-up authentication**

  ---

  Demand a recent or stronger login on sensitive routes.
- **Fails closed**

  ---

  Weak secrets, missing HTTPS and unenforceable scopes are refused, never skipped.

Coming from `fastapi.security`, fastapi-users or AuthX? See the [comparison](<https://fastapi-multiauth.d3vyce.fr/guide/comparison/index.md>).
