QAuth is an open-source identity server, designed from day one as a federation hub. Today it ships OAuth 2.1 / OIDC 1.0 with email/password authentication. The architecture β documented across ADR-003, ADR-004, and ADR-005 β is built so that wallet-based upstreams (EUDI Wallets via OID4VC / SIOPv2), external OIDC providers, and post-quantum signing algorithms slot in behind stable interfaces without changes to downstream applications. Applications integrate against QAuth's OIDC layer once.
Status: Early. Core OAuth 2.1 / OIDC flows are working; conformance hardening, observability, and the developer portal are in progress. See Current Status and the MVP milestone. Not yet recommended for production use.
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
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=..."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 and is design-stage today. Phase 1 signs JWTs with Ed25519; the hybrid transition is planned for Phase 5.
- 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 composite dual-signing β tokens will carry both an ML-DSA-65 and an Ed25519 signature, following the IETF LAMPS composite signatures model (draft-ietf-lamps-pq-composite-sigs). Both classical and post-quantum verifiers can validate without coordination.
// βοΈ Planned API β Phase 5 (2027 target, per ADR-005).
// @qauth-labs/crypto is not yet published. The interface below is a design
// sketch aligned with draft-prabel-jose-pq-composite-sigs.
import { signHybrid } from '@qauth-labs/crypto';
const token = await signHybrid(payload, { mlDsaKey, ed25519Key });Planned implementation:
@qauth-labs/crypto will be a native Node.js binding (napi-rs) wrapping aws-lc-rs (AWS-LC, a production-hardened BoringSSL fork with FIPS 140-3 validation in progress). This follows the same pattern as @node-rs/argon2 β prebuilt binaries per platform, no build tooling required for consumers. @noble/post-quantum (pure TypeScript, audited) is planned as the fallback for development environments and CI.
ADR-005 specifies a libs/core/crypto abstraction that will expose algorithm-agnostic sign / verify / generateKeyPair interfaces so that business logic is never coupled to a specific implementation. Swapping the underlying library will require no changes to the auth server.
Token size considerations:
ML-DSA-65 signatures are 3,309 bytes vs. Ed25519's 64 bytes. QAuth's architecture is being designed to default to reference tokens with introspection (RFC 7662) rather than large self-contained JWTs β mitigating HTTP header limits and cookie size constraints during the PQC transition period.
Migration timeline:
- Phase 1 (in progress): Ed25519 / EdDSA for JWT signatures, plus crypto-agile interfaces
- Phase 5 (2027 target): Hybrid composite ML-DSA-65 + Ed25519 (JOSE WG draft adopted Jan 2026)
- Future: FN-DSA (NIST FIPS 206, pending) evaluation β compact signatures (~666 B) may make self-contained PQC JWTs practical
A federated identity hub for the next generation of the internet:
- Federation-first β a single
federation-corelayer will normalise upstream identity (Verifiable Credential wallets, email/password, external OIDC providers, W3C DIDs) into a common internal model; downstream applications see standard OIDC tokens regardless of source - Wallet-agnostic β any standards-compliant VC wallet (OID4VC / SIOPv2) will be a valid upstream; 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, SIOPv2, W3C DID, NIST FIPS 204
- Open and self-hostable β Apache 2.0, no telemetry, runs anywhere
QAuth is early and not yet production-ready. An honest snapshot:
β Working today
- OAuth 2.1 authorization code flow with mandatory PKCE
- OIDC 1.0 userinfo + token introspection (RFC 7662)
- Email/password registration with Argon2id hashing
- JWT issuance, refresh, revocation (Ed25519)
- Email verification (Resend / SMTP / Mock providers)
- Multi-tenancy via Realms for data isolation
- PostgreSQL 18 + Redis 7 with Docker Compose
- OpenAPI / Swagger UI at
/docs - Phase 1.7 test coverage for JWT middleware, introspect, and userinfo
π§ In progress
- Developer portal skeleton (Phase 2)
- OIDC conformance items: ID tokens, nonce, scope/claims handling
- Structured logging (pino), Prometheus metrics, rate limiting
- Full OIDC discovery endpoint + JWKS
π Designed but not yet implemented
- Wallet federation (OID4VC / SIOPv2) β architecture in ADR-004
- Post-quantum hybrid signing β roadmap in ADR-005
@qauth-labs/cryptonative binding package- SDKs (
@qauth-labs/core,@qauth-labs/react,@qauth-labs/node) auth-ui(brandable login UI) andadmin-panel
Tracking: MVP milestone Β· ADR index Β· MVP-PRD
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Auth Server (TypeScript/Node.js) β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β API Layer (REST) β β
β β OAuth 2.1 Β· OIDC 1.0 (β
) β β
β β OID4VC Β· SIOPv2 (π 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/ π§ skeleton scaffolded (PR #137); Phase 2
β βββ 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 (ADR-003)
β β # password.provider.ts, wallet.provider.ts
β β # Normalises upstream β VerifiedIdentity
β β
β βββ fastify/plugins/ β
db Β· cache Β· email Β· jwt Β· password Β· pkce
β βββ 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/ π planned extraction (ADR-005)
β β βββ oauth/ # currently inlined in apps/auth-server
β β βββ oidc/ # currently inlined in apps/auth-server
β β βββ crypto/ # @qauth-labs/crypto β napi-rs + aws-lc-rs (Phase 5)
β β # @noble/post-quantum dev/CI fallback
β β
β βββ 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, and multi-tenancy via Realms. The MVP milestone tracks at 43 of 95 issues closed. The remaining Phase 1 work is OIDC conformance detail (ID tokens, nonce, claims), Prometheus + structured logging, rate limiting, and the developer-portal Dockerfile. See the MVP milestone.
Core authentication (working today):
- OAuth 2.1 / OpenID Connect 1.0 authorization code flow
- Email/password authentication with Argon2id hashing
- JWT token issuance, 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)
Developer tools:
- REST API (OAuth 2.1 / OIDC endpoints) β
- OpenAPI / Swagger UI at
/docsβ - Self-service developer portal π§ (Phase 2)
- TypeScript / React / Node.js SDKs π (Phase 3)
Phase 2 β Developer Portal:
- Self-service OAuth client registration and management
- API key management
- Federation provider configuration UI
Phase 3 β Production Hardening:
- OIDC 1.0 conformance (OpenID Foundation test suite)
- OIDC discovery + JWKS endpoint, ID tokens, nonce, scopes
- Rate limiting (Redis token bucket, per-IP and per-email)
- Security headers (Helmet: HSTS, CSP, X-Frame-Options)
- Prometheus metrics, Kubernetes manifests
Phase 4 β Wallet Federation Bridge (OID4VC / SIOPv2):
- SIOPv2 authentication request handling
- OID4VC Verifiable Presentation endpoint
- Trust anchor validation (extensible: EU Trusted List and other registries)
federation-core: normalises Verifiable Credentials β standard OAuth 2.1 tokens- 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
- 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 (planned, ADR-005):
@qauth-labs/cryptoβ native Node.js binding (napi-rs + aws-lc-rs);@noble/post-quantumin dev/CI
Frontend:
- Meta-framework: TanStack Start
- Framework: React 19
- Router: TanStack Router
- Data Fetching: TanStack Query
- Build Tool: Vite
- UI Primitives: Radix UI
- Styling: Tailwind CSS
- Tables: TanStack Table
- Forms: TanStack Form
Infrastructure:
- Monorepo: Nx 22.3+
- Package Manager: pnpm
- 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.
β οΈ Not yet recommended for production. Phase 3 (production hardening β rate limiting, security headers, metrics, Kubernetes manifests, OIDC conformance) is required before any production deployment.
# 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 -d- 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
- Structured logging (pino) + Prometheus metrics
- Rate limiting (Redis token bucket)
- Developer registration / login
- Self-service OAuth client management (CRUD)
- API key management
- Federation provider configuration UI
- OIDC 1.0 conformance (OpenID Foundation test suite)
- OIDC discovery (
/.well-known/openid-configuration) + JWKS endpoint - CSRF protection, security headers (Helmet)
- Kubernetes manifests
- JavaScript / React / Node.js SDKs (
@qauth-labs/core,@qauth-labs/react,@qauth-labs/node)
- SIOPv2 authentication request handling
- OID4VC Verifiable Presentation endpoint
- Trust anchor validation (extensible: EU Trusted List and other registries)
-
federation-corelibrary: VC wallet β standard OAuth 2.1 / OIDC tokens - Wallet login UI flow in
auth-ui - Inverse direction: QAuth as a Verifiable Credential issuer
- Integration tests against EUDI reference wallet
-
@qauth-labs/crypto: native Node.js binding (napi-rs + aws-lc-rs) - Hybrid composite ML-DSA-65 + Ed25519 JWT signing
- Reference-token architecture for PQC JWT size compatibility
- Crypto-agile abstraction layer (
sign/verify/generateKeyPair) -
@noble/post-quantumdev/CI fallback - Security review of cryptographic implementation
- 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
Available documentation:
- Product Requirements Document β full phase breakdown, API specs, database schema
- Docker Development Guide β local development with Docker
- Architecture Decision Records β key architectural decisions
- 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/shared-errors β centralized error handling
- @qauth-labs/shared-validation β input validation utilities
- @qauth-labs/shared-testing β test helpers and fixtures
Planned documentation (future phases):
- Quick Start Guide (external site)
- API Reference
- SDK Documentation (Phase 3)
- Authentication Flow guide
- 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. Phase 1 core flows work; Phase 1 conformance, observability, and Phase 2 (Developer Portal) are in progress. Not yet recommended for production use.
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, SIOPv2, NIST FIPS 204 (ML-DSA), W3C DID v1.0.