Skip to content

Authentication

Auth is always on. A fresh installation already requires a credential: out of the box the master key is the dev value meow and the JWT secret is meow_jwt, so the project works immediately but is never silently wide open.

Going to production is changing those two defaults in your config.py:

config.py
API_KEY = "a-very-long-and-alphanumeric-secret"
JWT_SECRET = "yet-another-very-long-and-alphanumeric-secret"

That is the whole story. The rest of this page explains what each one does.

Every request is authenticated from a single credential, sent as an Authorization: Bearer <credential> header (or an access_token cookie in the browser). That credential is one of two things:

Credential Who it is Use for
Master API key (API_KEY) The admin user Machine-to-machine calls
JWT Any user, with their roles Browsers and per-user sessions

API_KEY maps to a single, all-powerful admin user. Send it as-is:

let response = await fetch("http://localhost:1865/me", {
headers: { "Authorization": "Bearer meow" }
})
console.log(response.status, await response.json())

Without a valid credential you get:

403 {"detail": "Invalid Credentials"}

A JSON Web Token is a short-lived, per-user credential. It carries the user id and their roles, so no shared secret ever reaches the browser, and a stolen token expires on its own (JWT_EXPIRE_MINUTES, default 1 day).

The Cat verifies JWTs it signed with JWT_SECRET. It does not ship a built-in username/password login: minting a token is a login flow, and login flows are plugins. The simple_oauth plugin is the reference OAuth login you clone and point at Google, Auth0 or your own identity provider. Once logged in, the token is set as the access_token cookie and every following request is authenticated as that user.

Endpoints you add in plugins are open by default. Gate them by role right on the decorator:

from cat import endpoint, user
@endpoint.get("/admin/stuff", role="admin")
async def stuff():
return {"hi": user.name}

See Authorization for the role= semantics.

The final step is putting the Cat behind a reverse proxy with automatic TLS. Most open-source proxies manage certificates for you via Let’s Encrypt. Set HTTPS_PROXY_MODE = True in config.py so redirects behave correctly behind the proxy.