Skip to main content

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 plain sha256 (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' zerov4 security 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.json doesn'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 /panel dashboard
  • 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 after window_seconds has 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_seconds has 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)

Source distribution for brsxkeys 0.1.0
File Size Uploaded
brsxkeys-0.1.0.tar.gz 20.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for brsxkeys 0.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page