QAuth is an open-source OAuth 2.1 / OIDC 1.0 identity server built for three horizons at once:
- Agent era (today) — a working authorization server for MCP servers and AI agents: email/password auth,
authorization_code(PKCE) andclient_credentialsgrants, per-client audience (aud) binding, and agent-native, on-behalf-of delegation with scope modes and step-up (ADR-007). - Federation (by design) — a federation hub from day one: wallet-based upstreams (EUDI Wallets via OID4VC / OID4VP) and external OIDC providers slot in behind the
CredentialProviderinterface (ADR-003, ADR-004), so downstream applications integrate against QAuth's OIDC layer once and never change. - Post-quantum (for the long haul) — crypto-agile by construction: JWTs sign behind algorithm-agnostic interfaces today, with a clear hybrid ML-DSA-65 + Ed25519 transition path (ADR-005, ADR-006) that never touches application business logic.
MCP / AI-agent authorization ships today. Wallet federation works end-to-end against an OID4VP wallet and is E2E-tested, behind a default-off feature flag. Post-quantum hybrid signing is implemented behind a second default-off flag. One server, one integration, across all three.
🎉 July 2026 — the T4 platform track is nearly through. The MVP, the agent-native authorization layer (T2), production hardening (T3) and the environment-aware posture (T5) all shipped previously. Since then the identifier-abstraction migration (ADR-002, epic #224) and post-quantum hybrid signing (ADR-005, epic #241) have both landed, and wallet federation now completes a browser sign-in end-to-end behind a default-off flag. T4 stands at 48 issues closed, 4 open.
Status: Core OAuth 2.1 / OIDC and the MCP / agent-native authorization layer work end-to-end — discovery, dynamic client registration, resource-indicator audience binding, consent, and on-behalf-of agent delegation (the self-hostable OAuth 2.1 authorization server for MCP servers and AI agents; see ADR-007). Production hardening (T3) and the environment-aware authorization posture (T5, ADR-008) are complete; deploy with the documented production configuration. Wallet federation (T4) works end-to-end behind a flag — the OID4VP verifier, SD-JWT VC validation, key attestations and the claims pipeline are merged, and first-time login, returning login, account linking and
acremission are covered by an E2E suite driving a mock wallet over the wire. It is off by default (WALLET_FEDERATION_ENABLED=false) and validated only against theoid4vp-1.0-baseprofile; the HAIP profile and a real-wallet pass are still open. Post-quantum hybrid signing is implemented and default-off (HYBRID_SIGNING_ENABLED=false). See Current Status.
This project is developed with extensive AI assistance. Every change goes through human review before it is merged; even so, at this stage we cannot yet promise a high level of security assurance — use it with care and run your own evaluation before trusting it in sensitive or production deployments. Our long-term goal is enterprise-grade security with the lightest possible processing footprint: to that end, we are rewriting QAuth module by module in Rust.
The self-hostable auth server is what ships today. Run it locally with Docker Compose in a few minutes:
# Clone and start the stack (auth-server + Postgres 18 + Redis 7)
git clone https://github.com/qauth-labs/qauth.git
cd qauth
cp .env.docker.example .env # then add your JWT keys — see Quick Start below
docker compose up -d
# Verify
curl http://localhost:3000/healthYou can then drive it directly via the standard OAuth 2.1 / OIDC endpoints:
# Token endpoint — authorization code + PKCE (user-context)
curl -X POST http://localhost:3000/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=...&code_verifier=...&client_id=..."
# Token endpoint — client_credentials (service-to-service, RFC 6749 4.4)
# Client auth via HTTP Basic (client_secret_basic, RFC 6749 2.3.1)
curl -X POST http://localhost:3000/oauth/token \
-u "CLIENT_ID:CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&scope=read:foo"Interactive API docs (OpenAPI / Swagger UI) are served at /docs on the running instance.
Good fit for:
- Data sovereignty and GDPR requirements
- Self-hosted OAuth 2.1 / OIDC without the Keycloak footprint
- Organisations planning for eIDAS 2.0 wallet login as it lands (Phase 4)
📋 Planned — Phase 3+. The hosted QAuth backend and
@qauth-labs/coreSDK described in the examples below are not available yet. The self-hosted path above is the supported deployment today.
// 📋 Planned SDK surface — not yet published
import { QAuth } from '@qauth-labs/core';
const auth = new QAuth({
domain: 'auth.yourapp.com',
mode: 'headless',
});Target audience when available:
- Applications that need eIDAS 2.0 EUDI Wallet login without rewriting their auth layer
- Teams that want a headless API-first backend with custom branding
- Startups that want to skip identity infrastructure entirely
QAuth's PQC strategy is documented in ADR-005. The hybrid layer is implemented and merged (epic #241) — it is off by default and must be enabled deliberately. Ed25519 / EdDSA remains the shipping default for JWT signatures.
- ML-DSA-65 (NIST FIPS 204) — Digital signatures for JWT tokens. Level 3 (192-bit security), the minimum floor recommended by BSI (Germany) and ANSSI (France).
Defense in depth via detached-parallel dual-signing — tokens carry both an ML-DSA-65 and an Ed25519 signature, and the JWKS publishes mixed AKP + OKP key types (#246). Both classical and post-quantum verifiers validate without coordination; a classical Ed25519-only verifier needs no changes at all. See the Verifier Guide.
Enabling it:
# Off by default. Both variables are required; an ML-DSA key must also be set.
SIGNING_ALGORITHM_MODE=ed25519+ml-dsa-65
HYBRID_SIGNING_ENABLED=true
JWT_MLDSA_PRIVATE_KEY=<base64url 32-byte seed> # or JWT_MLDSA_PRIVATE_KEY_PATH
JWT_MLDSA_KID=<key id published in JWKS>Implementation:
The crypto layer lives in two internal workspace libraries: @qauth-labs/core-crypto (libs/core/crypto) provides the algorithm-agnostic sign / verify / generateKeyPair interfaces plus the @noble/post-quantum backend, and @qauth-labs/crypto-native (libs/core/crypto-native) is the napi-rs binding wrapping aws-lc-rs. Both are private workspace packages — neither is published to npm, and there is no standalone @qauth-labs/crypto release. Business logic is never coupled to a specific backend; the registry selects one at boot.
Token size considerations:
ML-DSA-65 signatures are 3,309 bytes vs. Ed25519's 64 bytes. QAuth therefore defaults to reference tokens with introspection (RFC 7662) when hybrid is on — PQC_TOKEN_DELIVERY=reference keeps the bearer a small Ed25519 JWS. Choosing self-contained ships a ~4.4 KB detached signature that exceeds cookie and URL budgets, so it additionally requires an explicit PQC_SELF_CONTAINED_ACK (#247).
Timeline:
- Shipping now: Ed25519 / EdDSA JWT signatures behind crypto-agile interfaces (the default posture)
- Shipping now, opt-in: hybrid detached-parallel ML-DSA-65 + Ed25519, mixed AKP+OKP JWKS, native
aws-lc-rsbackend - Before default-on: the pre-default-on checklist in the security gate review (CONDITIONAL PASS) must be cleared; the ML-DSA JOSE identifiers still track draft revisions
- Future: FN-DSA (NIST FIPS 206, pending) evaluation — compact signatures (~666 B) may make self-contained PQC JWTs practical
An identity hub for the next generation of the internet — humans, agents, and wallets on one server:
- Agent-native — first-class authorization for MCP servers and AI agents: an agent client type, RFC 8693 on-behalf-of delegation, scope modes, and step-up, so agents act for users under least privilege and full audit
- Federation-first — a single
federation-corelayer normalises upstream identity into a common internal model behind theCredentialProviderinterface; email/password runs on it in production today and the wallet path is merged, with external OIDC providers and W3C DIDs still to come. Downstream applications see standard OIDC tokens regardless of source - Wallet-agnostic — any standards-compliant VC wallet (OID4VC / OID4VP) is a valid upstream by design; EUDI Wallet under eIDAS 2.0 is one concrete deployment target, not the only one
- Post-quantum ready — crypto-agile architecture with a clear ML-DSA-65 hybrid transition path, designed so algorithm upgrades never touch application business logic
- Headless-first — API-first, bring your own branded UI
- Standards compliant — OAuth 2.1 (RFC 9700), OIDC 1.0, OID4VC, OID4VP, W3C DID, NIST FIPS 204
- Open and self-hostable — Apache 2.0, no telemetry, runs anywhere
🎉 Milestone reached. The MVP, the agent-native authorization track (ADR-007 §2), the T3 production-hardening track and the T5 environment-aware posture are all complete. The T4 platform track — identifier abstraction, wallet federation and post-quantum signing — is 48 issues closed with 4 open.
QAuth is feature-complete for MCP / agent authentication and production-hardened. An honest snapshot.
Phase 1 core OAuth 2.1 / OIDC, the MCP and agent-native authorization layers, the T3 production-hardening track (CSRF, security headers, secure cookies, OIDC ID token/nonce/claims, structured logging + /metrics, failed-login lockout), and the T5 environment-aware authorization posture (ADR-008 — environment as a fail-safe policy dimension + environment-gated developer API keys) are all complete and live-tested end-to-end.
Near-term focus — MCP / AI-agent auth. Building OAuth 2.1 properly produced a working authorization server for MCP servers and AI agents, validated end-to-end with Claude Code against a live MCP server. That remains the shipping product; T4 adds the federation and post-quantum platform beneath it. See ADR-007.
✅ Working today
- OAuth 2.1 authorization code flow with mandatory PKCE, including public clients (
none+ PKCE) client_credentialsandrefresh_tokengrants — rotation + family-based replay detection (RFC 9700)- Resource Indicators (RFC 8707) — audience-bound tokens across authorize → code → token → refresh
- Dynamic Client Registration (RFC 7591, open mode) + Authorization Server Metadata / OIDC discovery / JWKS
- Token introspection (RFC 7662), OIDC userinfo, consent screen + grant revocation
- Email/password registration + verification (Argon2id; Resend / SMTP / Mock), multi-tenancy via Realms
- Developer portal: registration / login / verify + dashboard shell (server-side
__Host-session) - PostgreSQL 18 + Redis 7 with Docker Compose; OpenAPI / Swagger UI at
/docs - Client-management API + developer-portal UI — full
/api/clientsCRUD with one-time secrets - Agent-native authorization (ADR-007 §2) — agent client type, RFC 8693 on-behalf-of token exchange (
actclaim), scope modes (ReadOnly / Admin / Exec), step-up before dangerous operations, and per-agent audit - Documentation — MCP quickstart, OAuth 2.1 flow, API reference, and the agent-authorization guide
@qauth-labs/mcp-guard— resource-server SDK: RFC 9728 protected-resource metadata + 401 challenge + token validation- Client ID Metadata Documents (CIMD) as the primary client-registration path (MCP 2026-07-28, which deprecates RFC 7591 dynamic registration); DCR stays supported as the documented backwards-compatibility fallback
- Trust floor: real-DB (testcontainers) repository tests + logout endpoint test + CI typecheck/coverage gate
- Security hardening (T3) —
@fastify/helmetsecurity headers (nonce-based CSP, HSTS, X-Frame-Options, X-Content-Type-Options), CSRF double-submit protection,__Host-secure cookies, and XSS-safe HTML output - OIDC conformance (T3) — ID token issuance (EdDSA) with
nonce, and alignedsub/email/email_verified/nameclaims across ID token, userinfo, and discovery - Observability (T3) — structured pino logging with secret redaction,
X-Request-Idpropagation, Prometheus/metrics(login + token counters), and Redis-backed failed-login tracking with lockout - developer-portal production Docker image + Docker Compose service
- Environment-aware authorization (T5, ADR-008) —
environment(development / staging / production) as a fail-safe, operator-set policy dimension on clients/realms; a singleresolveEnvironmentPolicyresolver drives token TTLs, PKCE, localhost redirects, rate-limit tier, agent step-up, and the T3 security bundle; plus environment-gated static developer API keys (backend + portal UI)
🚧 In progress — T4 platform track (48 closed / 4 open)
- Identifier abstraction (ADR-002) — complete. Epic #224 closed; migrations 0010–0012 shipped, including the destructive 0011 that dropped
users.email/password_hash.usersis now a pure identity anchor and all credential data lives inuser_credentials. This was the Phase 4 gate; it is passed. - Post-quantum hybrid signing (ADR-005) — implemented, default-off. Epic #241 closed: detached-parallel ML-DSA-65 + Ed25519, mixed AKP+OKP JWKS, native
aws-lc-rsbackend with a@noble/post-quantumfallback. Gated behindHYBRID_SIGNING_ENABLED=falsepending the security review checklist. - Wallet federation (ADR-004) — works end-to-end, off by default. Merged: OID4VP 1.0 request generation +
direct_postintake (#233),VerifierProfile(#299), per-realm issuer trust registry (#236), ES256 + JWE (#298), SD-JWT VC presentation validation (#234), Token Status List revocation (#297), HAIP key attestations (#308),acrpropagation from assurance level (#237, ADR-010), VC claims normalization (#235), account linking (#238), subject resolution strategy (#300), the wallet sign-in UI (#239) and an E2E mock-wallet suite (#240). A browser can complete a wallet sign-in — first-time enrolment, returning login, account linking andacremission are all covered end-to-end against a mock wallet speaking OID4VP 1.0 over the wire. SetWALLET_FEDERATION_ENABLED=trueto register the routes; the whole surface is inert while it is off, which is the default. Validated so far only against theoid4vp-1.0-baseprofile and a mock wallet. See the wallet sign-in guide. Note:WalletProvider.verify()— the genericCredentialProvider-registry entry point — still throws by design (#232). Wallet login does not go through it; it runs on the dedicated/ui/wallet-login+/oid4vp/responseseam. - Open: HAIP profile wiring (#377), key-storage assurance into the assurance policy (#379), the real-wallet interoperability pass (#376), and the tracking epic (#231).
📋 Not started — deferred beyond T4
- SDKs (
@qauth-labs/core,@qauth-labs/react,@qauth-labs/node),auth-ui,admin-panel - Hosted "Auth as a Service" backend
ADR-006 (OAuth grants —
client_credentials/client_secret_basic+audclaim) is implemented and shipping today, not deferred; the grants and audience binding above ship in the auth server now.
Tracking: MVP milestone · ADR index · MVP-PRD
┌──────────────────────────────────────────────────────┐
│ Auth Server (TypeScript/Node.js) │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ API Layer (REST) │ │
│ │ OAuth 2.1 · OIDC 1.0 (✅) │ │
│ │ OID4VC · OID4VP (📋 Phase 4) │ │
│ └────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────┐ │
│ │ federation-core (📋 Phase 2/4) │ │
│ │ • Upstream normalisation (VC wallet / OIDC / │ │
│ │ password → internal user model) │ │
│ │ • Downstream token issuance │ │
│ └────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Crypto Layer │ │
│ │ • JWT signing / verification │ │
│ │ ✅ Ed25519 via `jose` │ │
│ │ 📋 Phase 5 — native bindings via napi-rs │ │
│ │ • Password hashing ✅ Argon2id (@node-rs) │ │
│ │ • DID resolution 📋 Phase 6+ │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
↓ ↓
PostgreSQL 18 Redis 7
┌──────────────────────┐
│ API Gateway (TS) │
│ • REST │
└──────────────────────┘
↓ gRPC
┌─────┴─────┬─────────────┬──────────────┐
↓ ↓ ↓ ↓
┌────────┐ ┌─────────┐ ┌──────────┐ ┌─────────────┐
│ Auth │ │ Token │ │ Session │ │ Developer │
│ (TS) │ │ (TS) │ │ (TS) │ │ Portal (TS) │
└────────┘ └─────────┘ └──────────┘ └─────────────┘
Legend: ✅ implemented · 🚧 in progress · 📋 planned
qauth/
├── apps/
│ ├── auth-server/ ✅ Fastify OAuth 2.1 / OIDC 1.0 server
│ ├── developer-portal/ ✅ TanStack Start portal — auth, client CRUD, API keys
│ ├── migration-runner/ ✅ Drizzle migrations runner
│ ├── auth-ui/ 📋 planned — brandable login UI, Phase 2/4
│ └── admin-panel/ 📋 planned — Phase 6+
│
├── libs/
│ ├── server/
│ │ ├── config/ ✅ environment config + Zod validation
│ │ ├── jwt/ ✅ EdDSA signing / verification via `jose`
│ │ ├── password/ ✅ Argon2id via @node-rs/argon2
│ │ ├── pkce/ ✅ PKCE utilities
│ │ ├── email/ ✅ Resend / SMTP / Mock providers
│ │ └── federation/ ✅ CredentialProvider interface + registry (ADR-003)
│ │ # password.provider.ts — live in the auth engine
│ │ # wallet.provider.ts — verify() fail-closed (#232);
│ │ # wallet login uses the /ui/wallet-login seam
│ │ # Normalises upstream → VerifiedIdentity
│ │
│ ├── fastify/plugins/ ✅ db · cache · email · jwt · password · pkce · mcp-guard · federation
│ ├── infra/
│ │ ├── db/ ✅ PostgreSQL 18 + Drizzle ORM, repository pattern
│ │ └── cache/ ✅ Redis 7 connection + caching utilities
│ │
│ ├── shared/
│ │ ├── errors/ ✅ centralised error classes
│ │ ├── validation/ ✅ email / password validation utilities
│ │ └── testing/ ✅ test helpers and fixtures
│ │
│ ├── ui/ ✅ shared React primitives (early)
│ │
│ ├── core/
│ │ ├── crypto/ ✅ @qauth-labs/core-crypto — algorithm-agnostic
│ │ │ # sign/verify/JWE + @noble/post-quantum backend
│ │ ├── crypto-native/ ✅ @qauth-labs/crypto-native — napi-rs + aws-lc-rs
│ │ ├── oauth/ 📋 planned extraction — inlined in apps/auth-server
│ │ └── oidc/ 📋 planned extraction — inlined in apps/auth-server
│ │
│ └── sdk/ 📋 planned — Phase 3
│ ├── js/ # Vanilla JS SDK
│ ├── react/ # React SDK + hooks
│ └── node/ # Server-side SDK
│
└── services/ 📋 planned microservices — Phase 6+
├── token-service/ # Token generation (gRPC)
└── session-service/ # Session management (gRPC)
Status: Core OAuth 2.1 / OIDC flows work end-to-end with Ed25519 JWTs, Argon2id, PKCE, multi-tenancy via Realms, dynamic client registration, resource-indicator audience binding, and consent. The T3 hardening items — OIDC conformance detail (ID token, nonce, claims), structured logging + metrics, security headers, and the developer-portal Dockerfile — shipped under the T3 milestone (see ADR-007). For the full snapshot, see Current Status.
Core authentication (working today):
- OAuth 2.1 / OpenID Connect 1.0 authorization code flow
- OAuth 2.1
client_credentialsgrant for service-to-service auth (RFC 6749 4.4) - Client authentication via
client_secret_postandclient_secret_basic(RFC 6749 2.3.1) - Email/password authentication with Argon2id hashing
- JWT token issuance with
audandscopeclaims, refresh, and revocation (Ed25519 / EdDSA) - Token introspection (RFC 7662)
- OIDC userinfo endpoint
- Multi-tenancy via Realms for complete data isolation
- Mandatory PKCE on all authorization code flows
Infrastructure (working today):
- Email verification — Resend, SMTP, and Mock providers
- PostgreSQL 18 + Redis 7
- Docker deployment with automated migrations and health checks
- Structured audit logging (basic)
- Scriptable machine-client provisioning (
nx run db:db:seed-oauth-clients) — JSON-manifest-driven, idempotent, argon2id-hashed secrets; useful for bootstrappingclient_credentialsclients at deploy time, independently of the developer portal
Developer tools:
- REST API (OAuth 2.1 / OIDC endpoints) ✅
- OpenAPI / Swagger UI at
/docs✅ - Self-service developer portal ✅ (auth, client CRUD, API keys)
- TypeScript / React / Node.js SDKs 📋 (Phase 3)
Developer Portal (Phase 2 — shipped):
- Self-service OAuth client registration and management ✅ (
/api/clients+ portal UI) - API key management ✅ (environment-gated developer API keys, ADR-008)
- Federation provider configuration UI 📋 (not yet built — the T4 federation layer is currently configured through environment/realm config, not the portal)
Production Hardening (Phase 3 / T3 — shipped):
- OIDC discovery + JWKS endpoint, ID tokens, nonce, scopes ✅
- Rate limiting (Redis token bucket) ✅ (with the T5 environment rate-limit tier)
- Security headers (Helmet: HSTS, CSP, X-Frame-Options) ✅
- Prometheus metrics ✅
- OIDC 1.0 formal conformance (OpenID Foundation certification suite) 📋 — procedure written, run pending (runbook)
- Kubernetes manifests 📋
Phase 4 / T4 — Wallet Federation Bridge (OID4VC / OID4VP — works end-to-end, off by default):
- OID4VP 1.0 authorization request generation +
direct_postintake ✅ (#233) - SD-JWT VC Verifiable Presentation validation ✅ (#234)
- Trust anchor validation — static per-realm issuer allowlist ✅ (#236); EU Trusted List 📋
federation-core: normalises Verifiable Credentials →user_attributes✅ (#235)- Credential revocation via Token Status List ✅ (#297); HAIP key attestations ✅ (#308)
acrpropagation from assurance level ✅ (#237, ADR-010); account linking ✅ (#238)- Wallet sign-in UI ✅ (#239) + E2E mock-wallet suite ✅ (#240)
- Browser wallet sign-in completes end-to-end behind
WALLET_FEDERATION_ENABLED✅ - HAIP profile wiring 📋 (#377) · real-wallet interop pass 📋 (#376) · key-storage assurance 📋 (#379)
- Wallet login UI flow in
auth-ui - Inverse: QAuth as a Verifiable Credential issuer
Phase 5 — Post-Quantum Crypto:
@qauth-labs/crypto: native Node.js binding (napi-rs + aws-lc-rs)- Hybrid composite ML-DSA-65 + Ed25519 JWT signing (IETF LAMPS composite model)
- Reference-token architecture to handle PQC JWT size constraints
- Crypto-agile abstraction: algorithm swaps require no changes to business logic
@noble/post-quantumfallback for dev/CI environments
Phase 6+ — Enterprise & Scale:
- Social login (Google, GitHub, Microsoft)
- WebAuthn / Passkeys, TOTP / MFA
- SAML 2.0, LDAP / Active Directory
- W3C Decentralised Identifiers (DIDs)
- Organizations, Teams, advanced RBAC
- GraphQL API, webhook system
- Multi-region, CDN, microservices extraction
Backend:
- Runtime: Node.js 24 LTS
- Language: TypeScript 6.0
- Framework: Fastify
- API: REST (OAuth 2.1 / OIDC)
- ORM: Drizzle ORM
- Database: PostgreSQL 18
- Cache/Session: Redis 7
- Password hashing:
@node-rs/argon2(Rust native binding, Argon2id) - JWT (today):
jose(Ed25519 / EdDSA) - Crypto (shipped, default-off, ADR-005):
@qauth-labs/core-crypto+@qauth-labs/crypto-native— native Node.js binding (napi-rs + aws-lc-rs);@noble/post-quantumin dev/CI. Internal workspace packages, not published.
Frontend:
- Meta-framework: TanStack Start
- Framework: React 19
- Router: TanStack Router
- Data Fetching: TanStack Query
- Build Tool: Vite 8 (Rolldown)
- UI Primitives: Radix UI
- Styling: Tailwind CSS
- Tables: TanStack Table
- Forms: TanStack Form
Infrastructure:
- Monorepo: Nx 23
- Package Manager: pnpm 11
- Linting: ESLint 10
- Containerization: Docker
- Orchestration: Kubernetes ready (manifests planned, Phase 3)
- Observability: OpenTelemetry (planned, Phase 3)
- Cache/Session: Redis with ioredis
The easiest way to get started with QAuth locally is using Docker Compose. This will set up PostgreSQL, Redis, and the auth-server with a single command.
Prerequisites:
- Docker 20.10+ and Docker Compose 2.0+
- OpenSSL (for generating JWT keys)
Quick Start:
- Generate JWT keys (required for authentication):
# Generate EdDSA key pair
openssl genpkey -algorithm Ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem- Set up environment variables:
# Copy the example environment file
cp .env.docker.example .env
# Edit .env and add your JWT keys:
# JWT_PRIVATE_KEY="$(cat private.pem)"
# JWT_PUBLIC_KEY="$(cat public.pem)"- Start all services:
docker compose up -dThis will:
- Start PostgreSQL 18 (with uuidv7() support)
- Start Redis 7
- Build and start the auth-server
- Run database migrations automatically
- Expose the API on http://localhost:3000
- Verify the setup:
# Check service health
curl http://localhost:3000/health
# Browse interactive API docs
open http://localhost:3000/docs
# Check service logs
docker compose logs -f auth-serverAccessing Services:
- Auth API: http://localhost:3000
- API docs (OpenAPI / Swagger UI): http://localhost:3000/docs
- PostgreSQL: localhost:5432 (user:
qauth, password: from.envDB_PASSWORD) - Redis: localhost:6379
Running Migrations Manually:
Migrations run automatically via the migration-runner service before auth-server starts. You can also run them manually:
docker compose run --rm migration-runnerStopping Services:
docker compose down
# To also remove volumes (deletes all data):
docker compose down -vTesting the Setup:
A comprehensive test script is available to verify everything works:
./scripts/test-docker.shThis script will:
- Check environment configuration
- Build Docker images
- Start all services
- Run migrations
- Verify health checks
- Test API endpoints
- Verify data persistence
Troubleshooting:
- Port conflicts: If ports 3000, 5432, or 6379 are already in use, modify the port mappings in
docker-compose.yml - Migration errors: Check that PostgreSQL is healthy:
docker compose ps - JWT errors: Ensure your JWT keys are properly formatted in
.env(include BEGIN/END lines) - Build failures: Ensure you have enough disk space and Docker has sufficient resources allocated
- Migration runner fails: Check logs with
docker compose logs migration-runner
For more details, see the Docker documentation.
✅ Production hardening (T3) is complete — rate limiting, security headers, CSRF, secure cookies, OIDC conformance, and structured logging +
/metricsall ship. Deploy with the documented production configuration (strict cookies, HSTS,LOG_LEVEL, etc.). Kubernetes manifests remain a post-MVP item.
# Docker deployment (once tagged images are published)
docker run -p 3000:3000 qauth/auth-server
# Or with docker-compose
curl -O https://qauth.dev/docker-compose.yml
docker compose up -dNear-term direction is MCP-first (ADR-007). The tracks below set near-term priority; the numbered phases that follow remain the long-term plan, resequenced so wallet federation (Phase 4) and post-quantum signing (Phase 5) follow the MCP work.
- ✅ T0 — Trust floor: real-DB repository tests, logout endpoint test, CI typecheck + coverage gate
- ✅ T1 — MCP productization:
@qauth-labs/mcp-guard(RFC 9728 metadata + token validation + step-up scope challenges), Client ID Metadata Documents (CIMD) support, MCP quickstart + example, RFC 7009 revocation- ✅ T2 — Agent-native authZ (the Phase 9 substance, pulled forward): agent client type, RFC 8693 token-exchange delegation, scope modes (ReadOnly/Admin/Exec), step-up, per-agent audit
- ✅ T3 — OIDC conformance + hardening (done): security (CSRF/Helmet/secure cookies/XSS), observability (pino/
/metrics/request-id/failed-login lockout), ID token/nonce/claims, developer-portal Docker image- ✅ T5 — Environment-aware authZ (ADR-008) (done):
environmentas a fail-safe, operator-set policy dimension;resolveEnvironmentPolicydriving token TTLs / PKCE / localhost redirects / rate-limit tier / agent step-up / T3 bundle; environment-gated developer API keys (backend + portal UI)- 🚧 T4 — Federation + PQC (48 closed / 4 open): the ADR-002 migration gate is passed (epic #224); post-quantum hybrid signing is merged and default-off (epic #241); wallet federation works end-to-end behind
WALLET_FEDERATION_ENABLED, validated against a mock wallet on the base profile. Phases 4–5 below.
- Database schema design (PostgreSQL + Drizzle ORM, UUIDv7)
- Multi-tenancy via Realms
- Repository pattern with BaseRepository interface
- Centralised error handling (@qauth-labs/shared-errors)
- Core auth server (Fastify/TypeScript)
- Email/password authentication with Argon2id
- OAuth 2.1 authorization code flow + PKCE
- JWT issuance / refresh / revocation (EdDSA)
- Token introspection (RFC 7662), OIDC userinfo
- Email verification (Resend, SMTP, Mock providers)
- PostgreSQL + Redis setup
- Docker deployment with automated migrations
- OpenAPI / Swagger UI docs
- OIDC 1.0 ID tokens, nonce, scope/claims handling (T3)
- Structured logging (pino) + Prometheus metrics (T3)
- Rate limiting (Redis token bucket) (T3 + T5 environment tier)
- Developer registration / login
- Self-service OAuth client management (CRUD —
/api/clients+ portal UI) - API key management (environment-gated developer API keys, ADR-008)
- Federation provider configuration UI (not yet built — federation is configured via environment/realm config today)
- OIDC discovery (
/.well-known/openid-configuration) + JWKS endpoint (T3) - CSRF protection, security headers (Helmet) (T3)
- OIDC 1.0 formal conformance (OpenID Foundation certification suite)
- Kubernetes manifests
- JavaScript / React / Node.js SDKs (
@qauth-labs/core,@qauth-labs/react,@qauth-labs/node)
- OID4VP 1.0 authorization request generation +
direct_postintake (#233) - SD-JWT VC Verifiable Presentation validation (#234)
- Trust anchor validation — static per-realm issuer allowlist (#236)
-
federation-core: VC claims normalised intouser_attributes(#235) - Credential revocation via Token Status List (#297)
- HAIP Interoperable Key Attestations (#308)
-
acrpropagation from assurance level (#237, ADR-010) - Configurable subject resolution (#300) + account linking (#238)
- Wallet login UI flow (#239)
- Integration tests against a reference mock wallet (#240)
- Browser wallet sign-in completes end-to-end behind
WALLET_FEDERATION_ENABLED - HAIP profile wiring — signed
x509_hashrequests, encrypteddirect_post.jwt(#377) - Key-storage assurance into the assurance policy (#379)
- Real-wallet interoperability validation pass (#376)
- Trust anchor validation against the EU Trusted List
- Inverse direction: QAuth as a Verifiable Credential issuer
-
@qauth-labs/crypto-native: native Node.js binding (napi-rs + aws-lc-rs) (#244) - Hybrid detached-parallel ML-DSA-65 + Ed25519 JWT signing (#245)
- Mixed
AKP+OKPJWKS (#246) - Reference-token architecture for PQC JWT size compatibility (#247)
- Crypto-agile abstraction layer (
sign/verify/generateKeyPair) (#242) -
@noble/post-quantumdev/CI fallback (#243) - Security review of the cryptographic implementation (#248 — CONDITIONAL PASS)
- Verifier migration guide (#249)
- Clear the pre-default-on checklist and enable hybrid signing by default
- Social login (Google, GitHub, Microsoft)
- WebAuthn / Passkeys, TOTP / MFA
- SAML 2.0, LDAP / Active Directory
- W3C DIDs, advanced RBAC, Organizations & Teams
- GraphQL API, webhooks, multi-region, microservices extraction
📋 Not yet published. The SDK packages (
@qauth-labs/core,@qauth-labs/react,@qauth-labs/node) are planned for Phase 3. The examples below show the intended API surface — they will not work until the packages are released. For Phase 1 integration today, call the OAuth 2.1 / OIDC endpoints directly (see/docson a running instance).
// 📋 Planned — not yet published
npm install @qauth-labs/core
import { QAuth } from '@qauth-labs/core';
const auth = new QAuth({
domain: 'auth.yourapp.com',
projectId: 'your-project-id',
apiKey: 'your-api-key',
});
const { user, session } = await auth.signInWithPassword({
email: 'user@example.com',
password: 'password',
});
await auth.signUp({
email: 'newuser@example.com',
password: 'securepass',
metadata: { plan: 'pro' },
});
const session = await auth.getSession();// 📋 Planned — not yet published
import { QAuth } from '@qauth-labs/core';
const auth = new QAuth({
mode: 'self-hosted',
baseUrl: 'https://auth.yourcompany.com',
clientId: 'internal-app',
});
await auth.loginWithRedirect();// 📋 Planned — not yet published
import { QAuthProvider, useAuth } from '@qauth-labs/react';
function App() {
return (
<QAuthProvider
mode="self-hosted"
baseUrl="https://auth.yourcompany.com"
clientId="..."
>
<Dashboard />
</QAuthProvider>
);
}
function Dashboard() {
const { user, login, logout, loading } = useAuth();
if (loading) return <Spinner />;
if (!user) return <button onClick={login}>Login</button>;
return <div>Welcome {user.name}</div>;
}| Feature | Self-hosted (today) | Auth as a Service (planned) |
|---|---|---|
| Availability | ✅ Today (early) | 📋 Phase 3+ |
| Setup Time | ~15 min with Docker | 15 minutes |
| Infrastructure | You manage | None (hosted) |
| Custom Domain | ✅ | ✅ |
| Custom Branding | ✅ | ✅ |
| Data Location | Your servers | Our servers |
| Compliance | Full control | Standard |
| Pricing | Free (self-host costs) | Usage-based |
| Best For | Enterprise/Compliance | Startups/Products |
| Maintenance | You manage | Zero |
Self-hosted fits if:
- You have compliance requirements (GDPR, HIPAA, eIDAS 2.0)
- You need complete data sovereignty
- You're an enterprise with existing infrastructure
- You want to avoid vendor lock-in
Auth as a Service will fit (when available) if:
- You need custom branding without running infrastructure
- You're building a startup / product
- You want API-first headless auth
- You want to focus on your product, not identity plumbing
Guides (start at the docs index):
- MCP Quickstart — run QAuth + a
mcp-guard-protected MCP server and complete the full OAuth handshake end-to-end - OAuth 2.1 Flow — every endpoint with copy-paste
curl(PKCE, authorize, token, refresh, client_credentials, introspection) - Agent Authorization — the agent client type, RFC 8693 on-behalf-of delegation, scope modes, and step-up
- API Reference — hand-written contract for
/auth/*,/oauth/*, discovery, and/api/clients - Environment-Aware Authorization — the
environmentpolicy profile (dev/staging/prod) and environment-gated API keys - Browser Security — T3 hardening: security headers, CSRF, secure cookies, XSS-safe output
- Observability — structured logging,
/metrics, request-id, failed-login lockout - Code Examples — copy-paste Node/TS and browser (PKCE) clients
- Docker Development Guide — local development with Docker
- Wallet Sign-in (OID4VP) — the T4 browser wallet-login flow, the asserted-identifier step, and how to enable it
- Hybrid Signing — Verifier Guide — what token verifiers must do during the ADR-005 rollout (nothing, for classical Ed25519-only verifiers)
Reference:
- Product Requirements Document — full phase breakdown, API specs, database schema
- Architecture Decision Records — key architectural decisions
- PQC Security Gate Review — the three-dimension review of the merged PQC surface and the pre-default-on checklist
- EUDI Regulatory Drift Log — standing re-verification of the EU regulations ADR-004 and ADR-009 rest on
- OIDF OP Certification Runbook — the procedure for the OpenID Foundation conformance run
- Wallet Interop Manual Validation — the real-wallet validation procedure (#376)
- API docs (OpenAPI / Swagger UI) — served at
/docson the running instance
Library documentation:
- @qauth-labs/infra-db — database schema and repositories
- @qauth-labs/infra-cache — Redis caching utilities
- @qauth-labs/server-config — environment configuration
- @qauth-labs/server-email — email service with multiple providers
- @qauth-labs/server-password — password hashing with Argon2id
- @qauth-labs/server-jwt — JWT signing and verification
- @qauth-labs/server-pkce — PKCE challenge generation and verification
- @qauth-labs/server-federation —
CredentialProviderinterface, registry, and the password/wallet providers - @qauth-labs/core-crypto — algorithm-agnostic sign/verify/JWE and the hybrid PQC layer
- @qauth-labs/crypto-native — napi-rs binding over
aws-lc-rs - @qauth-labs/mcp-guard — resource-server SDK for protecting MCP servers
- @qauth-labs/fastify-plugin-federation — federation wiring for Fastify
- @qauth-labs/shared-errors — centralized error handling
- @qauth-labs/shared-validation — input validation utilities
- @qauth-labs/shared-testing — test helpers and fixtures
- @qauth-labs/ui — shared React primitives
Planned documentation (future phases):
- SDK Documentation (Phase 3)
- Multi-tenancy Guide
- Security Best Practices
We welcome contributions! See our Contributing Guide.
Apache License 2.0 — see LICENSE file for details.
Copyright © 2025–2026 QAuth Labs
Note: This project is under active development. Core OAuth 2.1 / OIDC, MCP / AI-agent auth, the T3 production-hardening track (security headers, CSRF, secure cookies, OIDC conformance, observability), and the T5 environment-aware authorization posture (ADR-008) all ship today. The T4 platform track is nearly through: the ADR-002 identifier migration is complete, post-quantum hybrid signing is merged and default-off, and wallet federation completes a sign-in end-to-end behind WALLET_FEDERATION_ENABLED — off by default, and so far validated only against a mock wallet on the oid4vp-1.0-base profile. Review the production configuration before deploying.
Inspired by: Keycloak, Ory, Auth0, Clerk, and Supabase Auth.
Standards and prior art this project builds on: OAuth 2.1 RFC 9700, OIDC Core 1.0, OID4VC, OID4VP, NIST FIPS 204 (ML-DSA), W3C DID v1.0.