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.
SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.comSCALEKIT_CLIENT_ID=skc_...SCALEKIT_CLIENT_SECRET=...COOKIE_ENCRYPTION_SECRET= # openssl rand -base64 32REDIRECT_URI=http://localhost:5001/callbackKeep COOKIE_ENCRYPTION_SECRET identical on every server instance.
Install the package
Section titled “Install the package”pip install "scalekit-sdk-python[fastapi]"Protect a route
Section titled “Protect a route”import osfrom fastapi import Depends, FastAPIfrom 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.
constructor
Section titled “constructor”#__init__
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.
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)install
Section titled “install”#install
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.
auth.install(app)requires_auth
Section titled “requires_auth”#asyncrequires_auth
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).
@app.get("/billing")async def billing(user: dict = Depends(auth.requires_auth)): return {"sub": user["sub"]}get_session
Section titled “get_session”#get_session
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.
session = auth.get_session(request)if session: print(session["user"]["sub"], session["expires_at"])