> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended**:
> ```bash
> npx @scalekit-inc/cli setup
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for 40+ agents.
> Skills: integrating-agentkit, implementing-saaskit, adding-mcp-oauth, implementing-modular-sso, implementing-scim-provisioning.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# FastAPI session middleware

Add hosted login and an encrypted session cookie to FastAPI with ScalekitAuth
Use `ScalekitAuth` from `scalekit.frameworks.fastapi` to add hosted login, an encrypted `sk_session` cookie, token refresh, and logout.

Typical flow: install the `fastapi` extra, call `auth.install(app)`, and protect an endpoint with `Depends(auth.requires_auth)`.

Requires `scalekit-sdk-python` 2.17.0 or later.

Register these URLs in the Scalekit Dashboard under **Authentication > Redirects** before you test:

| Dashboard field | Must match |
| --- | --- |
| **Redirect URI** | `redirect_uri` exactly, for example `http://localhost:5001/callback` |
| **Post Logout Redirect URI** | Absolute URL after full logout, for example `http://localhost:5001/` |
| **Initiate Login URL** | Login path, for example `http://localhost:5001/login` |

Store credentials in environment variables. Never hard-code secrets.

```bash title=".env" showLineNumbers=false
SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=skc_...
SCALEKIT_CLIENT_SECRET=...
COOKIE_ENCRYPTION_SECRET=   # openssl rand -base64 32
REDIRECT_URI=http://localhost:5001/callback
```

Keep `COOKIE_ENCRYPTION_SECRET` identical on every server instance.

## Install the package

```bash title="Terminal" showLineNumbers=false
pip install "scalekit-sdk-python[fastapi]"
```

## Protect a route

```python title="app.py" wrap showLineNumbers=false

from fastapi import Depends, FastAPI
from scalekit.frameworks.fastapi import ScalekitAuth

app = FastAPI()
auth = ScalekitAuth(
    env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"],
    client_id=os.environ["SCALEKIT_CLIENT_ID"],
    client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
    redirect_uri=os.environ["REDIRECT_URI"],
    cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"],
    cookie_secure=False,  # set True behind HTTPS
)
auth.install(app)

@app.get("/account")
async def account(user: dict = Depends(auth.requires_auth)):
    return {"sub": user["sub"]}
```

Open `http://localhost:5001/account`. A missing session returns **302** to `/login`, not a JSON 401.

`user` is access-token claims. `sub` is always present. `email` appears only when you add it as a custom access-token claim.

> caution: Set cookie_secure=False on local HTTP
>
> `cookie_secure` defaults to `True`. Set `cookie_secure=False` for local HTTP. Set it `True` in production.

<div class="sdk-client-page">

### constructor
<div class="sdk-method-section">
  
    

      Creates the FastAPI session helper. Call `install(app)` after construction to register routes and the 302 handler.

      
        Existing client. When omitted, the constructor builds one from `env_url`, `client_id`, and `client_secret`.
      
      
        Scalekit environment URL.
      
      
        Application client ID.
      
      
        Application client secret.
      
      
        Exact **Redirect URI** registered in the dashboard.
      
      
        Secret used to encrypt `sk_session`. Generate with `openssl rand -base64 32`.
      
      
        Session cookie name.
      
      
        Set `False` for local HTTP.
      
      
        Login route path.
      
      
        Callback route path.
      
      
        Logout route path.
      
      
        Fallback path after login when `returnTo` is absent.
      
      
        Where logout lands. Defaults to `post_login_redirect`.
      
      
        When `True`, logout ends the Scalekit session with `id_token_hint`.
      
      
        Helper with `install`, `requires_auth`, and `get_session`.
      

```python wrap showLineNumbers=false
auth = ScalekitAuth(
    env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"],
    client_id=os.environ["SCALEKIT_CLIENT_ID"],
    client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
    redirect_uri=os.environ["REDIRECT_URI"],
    cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"],
)
auth.install(app)
```

    
  
</div>

### install
<div class="sdk-method-section">
  
    

      Mounts the login, callback, and logout routes and registers the exception handler that turns a missing session into a 302.

      Call this once. `app.include_router(auth.router)` alone skips the 302 handler.

      
        FastAPI application.
      
      
        Routes and the redirect handler are registered in place.
      

```python wrap showLineNumbers=false
auth.install(app)
```

    
  
</div>

### requires_auth
<div class="sdk-method-section">
  
    
      

      FastAPI dependency. Use `user: dict = Depends(auth.requires_auth)`. Session check and refresh run in a thread pool so they do not block the event loop.

      
        Incoming request. Injected by FastAPI.
      
      
        Injected response. Receives a refreshed `sk_session` cookie when needed.
      
      
        Access-token claims. Missing session raises an internal error that `install` converts to 302, not `HTTPException(401)`.
      

```python wrap showLineNumbers=false
@app.get("/billing")
async def billing(user: dict = Depends(auth.requires_auth)):
    return {"sub": user["sub"]}
```

    
  
</div>

> note: Do not return a Response from a protected endpoint
>
> `requires_auth` writes the refreshed cookie on the injected `response`. If the endpoint returns a `Response` instance, FastAPI discards that injected response. Return a plain value, or copy `response.raw_headers` onto the response you return.

### get_session
<div class="sdk-method-section">
  
    

      Read-only session lookup. Does not refresh or write a cookie. Only `requires_auth` refreshes the session.

      
        Incoming request.
      
      
        `{"user": ..., "expires_at": ...}`, or `None`. Never includes `access_token`, `refresh_token`, or `id_token`.
      

```python wrap showLineNumbers=false
session = auth.get_session(request)
if session:
    print(session["user"]["sub"], session["expires_at"])
```

    
  
</div>

</div>


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
