API keys for FastAPI, in a few lines.
Authentication, per-key rate limits and usage tracking as one FastAPI dependency. SQLite by default, so there is nothing to set up.
pip install fastapi-keygate
The demo uses sample data. Keygate runs inside your own app, so your keys never leave your server.
- FastAPI
- SQLAlchemy
- SQLite by default
- Redis limits store
- Sync and async
- SHA-256 hashed keys
- Web dashboard
- CLI included
- MIT licensed
The whole quickstart
Protect a route, mint a key, and the limit is enforced per key. You import keygate; the PyPI package is fastapi-keygate.
from fastapi import Depends, FastAPI
from keygate import ApiKey, KeyGate
app = FastAPI()
gate = KeyGate(app, admin_secret="change-me") # SQLite, zero setup
@app.get("/hello")
def hello(key: ApiKey = Depends(gate.require)):
return {"hello": key.owner_id}
if not gate.list_keys(): # demo only: mint a first key
print("Your API key:", gate.create_key("demo-tenant", per_minute=5).key)$ uvicorn app:app
Your API key: kg_...
INFO: Uvicorn running on http://127.0.0.1:8000
$ curl -i localhost:8000/hello
HTTP/1.1 401 Unauthorized # no key
$ KEY=kg_... # the key the app printed
$ curl -H "X-API-Key: $KEY" localhost:8000/hello
{"hello":"demo-tenant"}
$ for i in 1 2 3 4; do curl -s -o /dev/null -w "%{http_code}\n" -H "X-API-Key: $KEY" localhost:8000/hello; done
200
200
200
200 # 5 requests so far, the limit is 5 per minute
$ curl -i -H "X-API-Key: $KEY" localhost:8000/hello
HTTP/1.1 429 Too Many Requests
Retry-After: <seconds>
$ keygate usage 1 # see what was countedTry the rate limit
A simulation running in your browser: a key limited to 5 requests per minute, like the quickstart. No request is sent anywhere.
Last response: none yet
What you get
Small surface, the parts most APIs end up hand-writing.
Hashed, shown once
Only a SHA-256 hash is stored. The plaintext key is returned once, at creation. Keys are read from X-API-Key or Authorization: Bearer, never from query strings.
Per-key rate limits
Requests per minute and/or hour, stored on each key. Over the limit returns 429 with Retry-After; responses carry X-RateLimit-* headers.
Usage tracking
Every authenticated request is logged with timestamp, method, route and status. Query totals by status and endpoint, and prune old rows.
Rotation with a grace period
gate.rotate(id, grace=timedelta(hours=24)) issues a replacement; the old key keeps working until the grace period ends.
Scopes and expiry
Guard routes with gate.require_scopes("write") (missing scope is 403). Keys can expire with expires_in=.
Sync and async
KeyGate for sync apps, AsyncKeyGate for async SQLAlchemy drivers, with the same features.
Web dashboard
Browse keys, usage charts and live rate-limit status; edit, rotate or revoke. Mount it with mount_dashboard(app, gate).
Opt-in plans
Optional per-owner plans cap key counts, per-key limits and scopes. Off unless you pass plans=. Billing is not included.
CLI included
keygate create, list, rotate, revoke, usage and prune work without writing code.
How it works
Limits belong to the key, so they are enforced inside the auth dependency.
- Create a keyFrom Python, the CLI, the admin API or the dashboard. You see the plaintext once.
- Client sends itIn the
X-API-Keyheader. The gate looks up the hash. - Gate checksValid, not revoked or expired, within its rate limit. Otherwise 401, 403 or 429.
- Request is loggedYour route runs and the usage row records route and status.
A dashboard, built in
Sign in with your admin secret. The online demo runs on seeded sample data.
Illustration only. Open the sample-data demo: enter any value to sign in. For your own data, run it locally.
Try it on your own machine
Keygate is a library, not a hosted service, so there is no page here to paste a key into. You run it yourself, and it creates and checks the keys for your API. These steps take about five minutes and need Python 3.9 or newer.
Install
In a terminal, in any empty folder:
python3 -m venv .venv && source .venv/bin/activate pip install -q -U fastapi-keygate uvicornThe
-Umatters: it replaces any older copy you already have.Start it
keygate quickstartThis starts a real, empty dashboard and one protected route,
/hello. It prints a dashboard link and an admin secret. Leave this terminal running.Sign in
Open the printed link and enter the admin secret.
Make a key
Go to API keys and click Generate key. Give it any name and owner. Set Per minute to 3 if you want to hit the limit quickly. The key is shown once, together with a ready-to-run command. Click Copy next to the command.
Use the key
Open a second terminal (the plus icon in VS Code, or a new tab) and paste the command. You get
{"hello":"..."}. Run it more times than your limit and you get429 Rate limit exceeded. Revoke the key from the ⋯ menu and the next call returns401. Overview shows every call.
Put it in front of OpenAI
The usual use: you run an endpoint that calls a paid API. Your callers use Keygate keys, each with its own limit, and your OpenAI key never leaves your server. Your OpenAI key is not a Keygate key and is never pasted into the dashboard.
Stop the quickstart
Press Ctrl+C in the terminal where it runs.
Get the example
pip install -q certifi curl -O https://raw.githubusercontent.com/codeSudee/fastapi-keygate/main/examples/openai_proxy.pycertififixes "could not reach OpenAI" on Python installed from python.org on macOS.Set your OpenAI key in this terminal
export OPENAI_API_KEY=your-openai-keyType your own key after the
=. It lives only in this terminal window. Never put it in the code or in git.Run it
python openai_proxy.pySign in to the printed link and generate a key as before.
Ask a question
curl -X POST localhost:8000/v1/ask -H "X-API-Key: YOUR_KEYGATE_KEY" -H "Content-Type: application/json" -d '{"prompt":"Say hi in five words"}'Replace
YOUR_KEYGATE_KEYwith the key you generated. You get a real answer. Calls over the key's limit are rejected before they reach OpenAI, so they cost nothing. Each successful call is billed by OpenAI as usual.
If something goes wrong
ImportError or version 0.4
An older copy is installed. Run pip install -U fastapi-keygate, inside a fresh virtual environment.
command not found: keygate
The virtual environment is not active in this terminal. Run source .venv/bin/activate first.
Address already in use
Something else is on port 8000. Stop it, or run keygate quickstart --port 8001 and use 8001 in the links.
"Not Found" in the browser
Open the /keygate/dashboard link the command printed, not just the bare address.
401 with a key
The key was copied wrongly, revoked or expired. Keys are shown once, so generate a new one.
"Could not reach OpenAI"
Install certifi (step above). The server terminal prints the real reason on the line starting OpenAI connection failed.
Status
Keygate is alpha (0.x). The API may change between minor versions. It is MIT licensed.
Not included yet: database migrations (tables are created on startup). With several workers, use a Redis limits store, since the default is per process. Feedback and bug reports are welcome as GitHub issues.