brsxkeys
Self-service API key management: users generate their own API keys,
choose a usage tier, and get rate-limited automatically. Comes with a
built-in dashboard (user side + admin panel) and a require_key
dependency you can drop into any other FastAPI project. FastAPI based.
⚠️ Security note: Like
brsxmail, this package does not provide production-grade security on its own. Passwords are hashed with plainsha256(no salt), sessions are kept in RAM (lost on restart, not shared across workers), and there's no CORS/brute-force protection beyond the per-key rate limiting described below. This package is designed to be used together with BRSX-Labs'zerov4security middleware for anything internet-facing or with real users. See "Using it together with zerov4" below.
Installation
pip install brsxkeys
or clone this repo and:
pip install -e .
Two ways to use this package
1. As a full dashboard (self-service key generation, usage stats, admin panel):
from brsxkeys import keys
keys.run()
2. As a dependency in your own separate FastAPI project (just the key-checking logic, no dashboard):
from brsxkeys import keys
from fastapi import Depends
@app.get("/private", dependencies=[Depends(keys.require_key)])
def private():
return {"msg": "only visible with a valid API key"}
Both read/write the same config and storage, so keys created via
the dashboard are immediately usable by require_key in your other
project (as long as they point at the same data_dir).
Running the dashboard
Quick start
python run.py
- On first run, if
brsxkeys.config.jsondoesn't exist, an interactive setup wizard opens in the terminal. It asks for:- domain (for user email registration)
- port, host
- storage type (json/sqlite)
- data folder name
- tier definitions — you name each tier (e.g.
free,pro) and set its request limit and time window (e.g. 100 requests / 86400 seconds = 1 day); add as many tiers as you want, empty input to finish - interface preference for the user side (built-in vs. your own HTML)
- admin account (email + password) for the
/paneldashboard
- On subsequent runs, the wizard isn't asked again — the server starts directly.
- To reset settings:
python run.py --reconfigure
Via CLI after pip install
brsxkeys
brsxkeys --reconfigure
The simplest usage
from brsxkeys import keys
keys.run()
From code (advanced)
from brsxkeys import create_app, get_or_create_config
import uvicorn
config = get_or_create_config()
app = create_app(config)
uvicorn.run(app, host=config["host"], port=config["port"])
The two sides of the dashboard
/ — user side
- Register / login (same domain-restricted email system as
brsxmail) - Pick a tier and generate your own API key (self-service — no admin approval needed)
- See all your own keys, their tier, active/inactive status, and usage
(
used/limit, reset window) - Revoke your own keys
This side can be customized: place your own index.html in the
folder where you run the server, and choose "I'll use my own index.html"
in the wizard. Same mechanism as brsxmail — if the file is missing,
a clear warning is printed to the terminal and it falls back to the
built-in interface.
/panel — admin side
- Login with the admin account created during setup (a real account
with
role: "admin", stored the same way as regular users, just flagged differently) - View tier definitions
- View every key across every user, with the same usage stats the user side shows, plus the owner's email
- Revoke any key, regardless of owner
/panel is always the built-in interface — it is never affected
by use_custom_html. Only / can be customized.
Writing your own interface for "/"
The server reads your index.html and fills in these placeholders:
{{LOGGED_IN}}→"true"/"false"{{USER}}→ the logged-in user's email (empty if not logged in){{DOMAIN}}→ the domain from config (e.g.@brsx.com){{TIERS}}→ comma-separated list of tier names (e.g.free,pro)
API contract (dashboard endpoints)
General rule: All POST endpoints expect form-data. All
responses are JSON. Session is a cookie (session_id) set after login.
| Method | Path | Body | Fields | Auth needed | Returns |
|---|---|---|---|---|---|
| GET | / |
— | — | — | HTML |
| POST | /register |
form-data | email, password |
— | {ok} / {error} |
| POST | /login |
form-data | email, password |
— | {ok, role} / {error} |
| POST | /logout |
— | — | — | {ok} |
| GET | /tiers |
— | — | — | tier definitions (dict) |
| POST | /keys/create |
form-data | tier |
user login | {ok, key} |
| GET | /keys |
— | — | user login | list of your own keys w/ usage |
| DELETE | /keys/{key} |
— | — | user login | {ok} / {error} |
| GET | /panel |
— | — | — | HTML (admin login form) |
| GET | /panel/keys |
— | — | admin login | list of ALL keys w/ usage |
| DELETE | /panel/keys/{key} |
— | — | admin login | {ok} / {error} |
| GET | /panel/tiers |
— | — | admin login | tier definitions (dict) |
Each key object looks like:
{
"key": "bxk_...",
"owner": "dev@your-domain.com",
"tier": "free",
"active": true,
"created_at": 1785082921.9,
"usage_count": 3,
"limit": 100,
"window_seconds": 86400
}
For a working example, check the bundled brsxkeys/webui/index.html
and brsxkeys/webui/panel.html — real, working JS examples of all
these calls.
require_key: protecting endpoints in your own project
from brsxkeys import keys
from fastapi import Depends
@app.get("/private", dependencies=[Depends(keys.require_key)])
def private():
...
# or, if you need to know the caller's tier/owner inside the endpoint:
@app.get("/private")
def private(key_info: dict = Depends(keys.require_key)):
return {"tier": key_info["tier"], "owner": key_info["owner"]}
The key can be sent either way — both are supported:
curl -H "X-API-Key: bxk_..." http://localhost:8000/private
curl "http://localhost:8000/private?api_key=bxk_..."
Behavior:
- No key sent →
401 Missing API key - Invalid key →
401 Invalid API key - Key exists but inactive/revoked →
403 API key is inactive or revoked - Quota exceeded for the current window →
429, and the key is deactivated until you manually reactivate it or it's naturally reset (the usage window resets automatically the next time the key is checked afterwindow_secondshas elapsed)
require_key reads config/storage lazily on first use — importing
brsxkeys doesn't trigger the setup wizard by itself; it only runs
when a protected endpoint is actually hit for the first time.
Using it together with zerov4
Same pattern as brsxmail. Use blocking=False to get the FastAPI
app without starting uvicorn, then hand it off to zerov4:
# main.py
from brsxkeys import keys
from zerov4 import arx
app = keys.run(blocking=False) # only creates the dashboard app
arx.run(app) # zerov4 wraps it and starts the server
This protects the dashboard itself (registration, login, key
creation) with zerov4's bot/brute-force/session-hijacking defenses.
Note this is separate from require_key, which protects endpoints in
some other app of yours that consumes brsxkeys as a library.
Storage
Default: JSON file based (data_dir/users.json, data_dir/keys.json,
data_dir/usage.json). If sqlite is chosen in the setup wizard, a
single brsxkeys.db is used instead. Both backends implement the same
interface.
Notes
- Rate limiting is per-key, per-tier, using a fixed time window (not
a sliding window): once
window_secondshas elapsed since the window started, usage resets to 0 on the next check. - When a key exhausts its quota mid-window, it is deactivated
(
active: false) rather than just throttled; the user (or admin) can see this reflected in the dashboard. - Domain checking defaults to
@example.com, changeable in the setup wizard.
Release files for brsxkeys 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| brsxkeys-0.1.0.tar.gz | 20.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| brsxkeys-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.7 kB
Release files / brsxkeys-0.1.0.tar.gz
| Download URL | brsxkeys-0.1.0.tar.gz |
|---|---|
| Size | 20.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
012b6c8311e4ce1a65c2cf5e1c3f17f97193f252815fc6e8011fc335cbc23d14
|
|
BLAKE2b-256 checksum How to use checksums |
146cbd33b345e9165d953cc64c675885029c023b93f5081a3ee0b7ef45d6e459
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.0
|
Release files / brsxkeys-0.1.0-py3-none-any.whl
| Download URL | brsxkeys-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c40067a5dd8a78973892678b16bb95abb90b7026fc5a89fefd7675f89b28394b
|
|
BLAKE2b-256 checksum How to use checksums |
e84fdf47ca35b61745374710e986e646745813af57d044026d3a0bce89e829bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.0
|