Keygate
Alpha, v0.5 on PyPI

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.

app.py
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)
terminal
$ 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 counted

Try 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.

GET /helloSimulation
5 of 5 remaining

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.

  1. Create a keyFrom Python, the CLI, the admin API or the dashboard. You see the plaintext once.
  2. Client sends itIn the X-API-Key header. The gate looks up the hash.
  3. Gate checksValid, not revoked or expired, within its rate limit. Otherwise 401, 403 or 429.
  4. 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.

  1. Install

    In a terminal, in any empty folder:

    terminal
    python3 -m venv .venv && source .venv/bin/activate
    pip install -q -U fastapi-keygate uvicorn

    The -U matters: it replaces any older copy you already have.

  2. Start it

    terminal
    keygate quickstart

    This starts a real, empty dashboard and one protected route, /hello. It prints a dashboard link and an admin secret. Leave this terminal running.

  3. Sign in

    Open the printed link and enter the admin secret.

  4. 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.

  5. 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 get 429 Rate limit exceeded. Revoke the key from the ⋯ menu and the next call returns 401. 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.

  1. Stop the quickstart

    Press Ctrl+C in the terminal where it runs.

  2. Get the example

    terminal
    pip install -q certifi
    curl -O https://raw.githubusercontent.com/codeSudee/fastapi-keygate/main/examples/openai_proxy.py

    certifi fixes "could not reach OpenAI" on Python installed from python.org on macOS.

  3. Set your OpenAI key in this terminal

    terminal
    export OPENAI_API_KEY=your-openai-key

    Type your own key after the =. It lives only in this terminal window. Never put it in the code or in git.

  4. Run it

    terminal
    python openai_proxy.py

    Sign in to the printed link and generate a key as before.

  5. Ask a question

    second terminal
    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_KEY with 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.