Cursor Agent 88c0c4a453 Fix Authelia OIDC state check and hide redirect URI on login
Auth.js OIDC defaults to PKCE-only, so no `state` was sent; Authelia
rejects that. Enable checks: pkce + state. Remove the public redirect
URI hint from the login page.
2026-08-24 04:12:34 +00:00

RFID Database

PWA + REST API for storing LF/HF RFID tag dumps organized by site. Use the web UI in the field, or call /api/v1 from scripts (and a future Proxmark CLI).

Features

  • Sites (A, B, C, …) with tag records (UID, protocol, keys, full dump)
  • Multi-user auth (shared workspace, no RBAC yet) — local password + optional OIDC
  • Personal API tokens (Settings UI) for Bearer auth
  • Export: JSON, Proxmark, MCT, hex
  • Import dumps + full JSON backup
  • Installable PWA with offline read of cached pages
  • Vitest unit/integration tests + GitHub Actions CI

Quick start

cp .env.example .env
# set AUTH_SECRET to a long random string

npm install
npm run create-user -- --email [email protected] --password 'changeme' --name You
npm run dev

Open http://localhost:3000 and sign in.

Environment

Variable Required Description
AUTH_SECRET yes NextAuth secret
AUTH_URL recommended Public app URL (e.g. https://rfid.example.com)
RFID_DB_PATH no SQLite path (default ./data/rfid.db)
AUTH_OIDC_ISSUER for OIDC Issuer URL (must expose /.well-known/openid-configuration)
AUTH_OIDC_CLIENT_ID for OIDC OIDC client id
AUTH_OIDC_CLIENT_SECRET for OIDC OIDC client secret
AUTH_OIDC_NAME no SSO button label (default SSO)

Enabling OIDC

  1. Pull latest and rebuild (OIDC button detection changed recently):
    git pull
    docker compose up -d --build
    
  2. In your IdP, create a confidential OIDC application.
  3. Set the redirect / callback URI to exactly:
    {AUTH_URL}/api/auth/callback/oidc
    
    Example: https://rfid.atlashorizon.net/api/auth/callback/oidc
  4. Put these in .env:
    AUTH_URL=https://rfid.atlashorizon.net
    AUTH_SECRET=...long random...
    AUTH_OIDC_ISSUER=https://auth.atlashorizon.net
    AUTH_OIDC_CLIENT_ID=rfiddb
    AUTH_OIDC_CLIENT_SECRET=...
    AUTH_OIDC_NAME=AtlasHorizon
    
  5. Restart, then verify the running app sees config (no secrets returned):
    curl -s https://rfid.atlashorizon.net/api/v1/auth/config | jq
    
    You want "oidcEnabled": true and "callbackUrl" matching your IdP.
  6. Open /login — you should see Sign in with AtlasHorizon.

Notes:

  • AUTH_OIDC_ISSUER must match discovery ({issuer}/.well-known/openid-configuration). Your AtlasHorizon issuer at https://auth.atlashorizon.net is valid.
  • The IdP must return an email claim (we request openid email profile).
  • Local password login stays available alongside SSO.
  • If the button is missing, you are almost certainly on an old image — rebuild.

REST API (/api/v1)

Authenticate with a session cookie or Authorization: Bearer rfid_… (create tokens under Settings → API tokens).

Method Path Purpose
GET/POST /api/v1/sites List / create sites
GET/PATCH/DELETE /api/v1/sites/{id} Site detail
GET/POST /api/v1/tags List / create tags
GET/PATCH/DELETE /api/v1/tags/{id} Tag detail
PUT /api/v1/tags/by-uid/{uid}?siteId= Upsert by UID
GET /api/v1/tags/{id}/export?format= json | proxmark | mct | hex
POST /api/v1/tags/import Parse dump → create tag
GET /api/v1/search?q= Cross-site search
GET/POST /api/v1/backup Full backup export / import
GET/POST /api/v1/tokens List / create PATs
DELETE /api/v1/tokens/{id} Revoke PAT
GET /api/v1/me Current user

curl examples

# Create a token in the UI first, then:
export TOKEN=rfid_…
export HOST=http://localhost:3000

curl -sH "Authorization: Bearer $TOKEN" "$HOST/api/v1/sites"

curl -sH "Authorization: Bearer $TOKEN" \
  "$HOST/api/v1/tags/$ID/export?format=proxmark" -o dump.json

curl -sH "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -X PUT "$HOST/api/v1/tags/by-uid/04A1B2C3?siteId=$SITE" \
  -d '{"label":"Dock fob","frequency":"HF","protocol":"MIFARE_CLASSIC_1K","uid":"04A1B2C3","dumpData":{"size":"1K","sectors":[]},"keys":{"A":["FFFFFFFFFFFF"]}}'

Tests & CI

npm test
npm run lint
npm run typecheck
npm run build

GitHub Actions on every pull request and push to main:

  1. lint / typecheck / test / Next.js build
  2. Docker image — build on PRs; on main (and v* tags) push to GHCR: ghcr.io/chewbaccalakis/rfid-database

Pull the published image

docker pull ghcr.io/chewbaccalakis/rfid-database:latest
# or a specific commit: ghcr.io/chewbaccalakis/rfid-database:sha-<shortsha>

If the package is private, authenticate first:

echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin

Or in Compose, set image: ghcr.io/chewbaccalakis/rfid-database:latest and comment out build:.

Docker

cp .env.example .env
# set AUTH_SECRET to a long random string

# optional first user on boot:
# echo '[email protected]' >> .env
# echo 'CREATE_USER_PASSWORD=changeme' >> .env

docker compose up -d --build

App: http://localhost:3000 — SQLite persists in the rfid-data volume.

Create a user later (if you skipped bootstrap):

docker compose exec rfid-database \
  npx tsx scripts/create-user.ts --email [email protected] --password 'secret' --name You

Stop / remove (keeps volume):

docker compose down

Plain docker

docker build -t rfid-database .
docker run --rm -p 3000:3000 \
  -e AUTH_SECRET=your-long-secret \
  -e CREATE_USER_EMAIL=[email protected] \
  -e CREATE_USER_PASSWORD=changeme \
  -v rfid-data:/data \
  rfid-database

Security

Tag dumps often include sector keys. Keep the app behind HTTPS, do not expose it publicly without auth, and treat data/rfid.db as sensitive.

S
Description
No description provided
Readme
213 KiB
Languages
TypeScript 93.3%
CSS 3.3%
JavaScript 1.5%
Dockerfile 1.4%
Shell 0.5%