Because passwords SUCK!
Self-hosted passwordless magic-link auth service.
- Passhroom API service (Node.js + TypeScript + Fastify)
- Postgres migrations
- CLI for client management (create/rotate/enable/disable + allowlists)
- Docker Compose template + Nginx templates for reverse proxy setups
- Public docs for design, authentication, and generic deployment
- Copy env template:
cp .env.example .env
- Edit
.envand set required values:
PASSHROOM_DB_PASSWORDCOOKIE_SECRET(long random value)PASSHROOM_PUBLIC_BASE_URL(for examplehttps://auth.example.com)- SMTP settings (
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_FROM)
- Start services:
docker compose -f docker-compose.passhroom.yml up -d --build
- Run migrations:
docker exec -it passhroom-api sh -lc "cd /app && npm run migrate:up"
- Verify health:
curl -i -H 'x-forwarded-proto: https' http://127.0.0.1:18080/healthz
This repo supports an optional private operations docs submodule at servertron-docs.
- Public users can skip submodule initialization entirely.
- Maintainers can initialize it with:
git submodule update --init -- servertron-docs
The submodule contains private infrastructure and server automation material that is intentionally not required for building, testing, running, or self-hosting Passhroom.
Project maintainer note:
- I use
servertron-docsfor my own private operations workflow. - If you are self-hosting Passhroom, you do not need
servertron-docsand should deploy using your own infrastructure approach.
Maintainer note:
- Private deploy scripts live at
servertron-docs/apps/passhroom/scripts/. - Private deploy config lives at
servertron-docs/apps/passhroom/.deploy.env.
- Configure env:
cp .env.example .env and fill required values (PASSHROOM_DB_PASSWORD, COOKIE_SECRET, PASSHROOM_PUBLIC_BASE_URL, SMTP vars).
- Start services:
docker compose -f docker-compose.passhroom.yml up -d --build
- Run migrations + route HTTPS:
docker exec -it passhroom-api sh -lc "cd /app && npm run migrate:up", then point your reverse proxy domain to Passhroom (127.0.0.1:18080 by default).
- Architecture/design:
docs/design.md - Auth flow and security model:
docs/authentication.md - Generic deployment notes:
docs/deployment.md - App integration examples:
docs/pashroom-app-integration-guide.md - Legacy/private host automation notes:
servertron-docs/apps/passhroom/README.md(maintainers only)
Passhroom includes an admin-only dashboard for viewing users and testing auth flow endpoints.
- Enable in
.env:ADMIN_ENABLED=true - Visit:
https://<your-domain>/admin/login
Compose reads env vars from root .env (copy from .env.example).
- Required:
PASSHROOM_DB_PASSWORDCOOKIE_SECRETPASSHROOM_PUBLIC_BASE_URLSMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_FROM
- Recommended in production:
NODE_ENV=productionREQUIRE_HTTPS=true
Run from inside the API container (or locally with DATABASE_URL configured):
- Create client:
node dist/cli.js clients:create --client-id myapp --redirect-uri https://myapp.com/auth/callback --allowed-origin https://myapp.com
- Rotate secret:
node dist/cli.js clients:rotate-secret --client-id myapp
curl -X POST https://auth.example.com/v1/auth/start \ -H 'content-type: application/json' \ -d '{"client_id":"myapp","email":"me@example.com","redirect_uri":"https://myapp.com/auth/callback","state":"opaque-csrf"}'
curl -X POST https://auth.example.com/v1/auth/token \ -H 'content-type: application/json' \ -d '{"client_id":"myapp","client_secret":"<secret>","code":"<code>","redirect_uri":"https://myapp.com/auth/callback"}'
- Tokens/codes are generated with CSPRNG and only hashes are stored.
- Redirect URIs are exact-match allowlisted per client.
- Keep
.envprivate; it is intentionally gitignored. - Configure SPF/DKIM/DMARC for your sender domain.
MIT (see LICENSE).