Skip to content

Add SQLite storage and JWT auth with MFA/RBAC for the admin API - #123

Merged
GyulyVGC merged 12 commits into
NullNet-ai:mainfrom
antoncxx:investigate/sqlite-storage
Jul 27, 2026
Merged

Add SQLite storage and JWT auth with MFA/RBAC for the admin API#123
GyulyVGC merged 12 commits into
NullNet-ai:mainfrom
antoncxx:investigate/sqlite-storage

Conversation

@antoncxx

@antoncxx antoncxx commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

The nullnet-server admin API and web UI had no authentication at all. This PR adds:

  • A SQLite storage backend (Diesel + diesel-async) as the foundation for everything below.
  • JWT-based login with two roles (admin / user) and per-user, per-resource scopes
    (certificates, config, sessions, nodes, events — read/write where applicable).
  • Optional TOTP MFA (QR-code setup, not mandatory, with a UI nudge banner until it's enabled).
  • A Login page, a Users admin page (create/edit/delete, scope assignment), and silent
    access-token refresh on the frontend.

What's included

Storage (src/db/)

  • New Diesel migrations for users, user_scopes, refresh_tokens, login_attempts, alongside
    the pre-existing certificates/dns_credentials/services tables.
  • Migrations run automatically on startup via diesel_migrations inside spawn_blocking.

Auth core (src/auth/)

  • argon2 password hashing, totp-rs-based TOTP (RFC 6238), jsonwebtoken (HS256) access
    tokens (15 min TTL), opaque DB-revocable refresh tokens (SHA-256 hashed, 30-day TTL,
    rotate-on-use).
  • A second, independent encryption key (MFA_ENCRYPTION_KEY) for TOTP secrets at rest — kept
    separate from CERT_ENCRYPTION_KEY so the two secret classes don't share blast radius.
  • Idempotent admin bootstrap (ADMIN_BOOTSTRAP_USERNAME/ADMIN_BOOTSTRAP_PASSWORD), a no-op
    once any user exists; falls back to admin/admin with a loud startup warning if unset.
  • Per-username lockout after 5 failed attempts (15 min), shared by both the password step and
    the MFA-verify step of login.

HTTP API (src/http_server/auth/)

Method Path Auth Notes
POST /api/auth/login public password step; returns an mfa_token if MFA is enabled
POST /api/auth/mfa/verify public TOTP step; issues session cookies
POST /api/auth/refresh public (refresh cookie) rotates both cookies
POST /api/auth/logout protected revokes refresh token, clears cookies
GET /api/auth/me protected id/username/role/scopes/mfa_enabled
POST /api/auth/mfa/setup | /confirm | /disable protected TOTP provisioning/confirm/disable
GET/POST/PATCH/DELETE /api/auth/users[/{id}] protected, admin-only user CRUD

Every pre-existing route (certificates, config, sessions, nodes, events, graph,
chains, stacks, services) now sits behind require_auth middleware plus a require_scope
check matching its resource.

Frontend (ui/)

  • AuthContext, RequireAuth, apiFetch (auto-refresh-then-redirect on 401).
  • Login page, Users admin page, MfaSetupDialog, and a first-ever Modal component.
  • An MFA warning banner in the main layout when MFA isn't enabled yet, with a one-click setup
    flow.

Config

New required env vars (server refuses to start without JWT_SIGNING_KEY/MFA_ENCRYPTION_KEY):

JWT_SIGNING_KEY=<32 raw bytes or 64 hex chars>
MFA_ENCRYPTION_KEY=<32 raw bytes or 64 hex chars>
DATABASE_URL=/var/nullnet/data/nullnet.db   # optional, default shown
ADMIN_BOOTSTRAP_USERNAME=admin              # optional, first-run only
ADMIN_BOOTSTRAP_PASSWORD=<a real password>  # optional, first-run only

See README.md for the full rundown.

@antoncxx antoncxx changed the title Investigate/sqlite storage Add SQLite storage and JWT auth with MFA/RBAC for the admin API Jul 25, 2026
@antoncxx
antoncxx marked this pull request as ready for review July 25, 2026 03:21
@GyulyVGC GyulyVGC added the enhancement New feature or request label Jul 25, 2026
@GyulyVGC
GyulyVGC merged commit 0058c6b into NullNet-ai:main Jul 27, 2026
4 checks passed
@antoncxx
antoncxx deleted the investigate/sqlite-storage branch July 27, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants