Getting Started
Introduction
What Auth Service is, when to use it, and how it fits into your stack.
Introduction
Auth Service is a self-hosted OAuth 2.1 / OIDC identity provider built on BetterAuth v1.5. It issues signed JWTs that carry per-application roles, permissions, and subscription feature flags so downstream services can make access-control decisions without calling back to the auth server.
When to use Auth Service
Use Auth Service when you need:
- A private, self-hosted identity provider with no dependency on external services (Auth0, Cognito, etc.)
- A single auth layer shared across several independent applications, each with their own role set
- Subscription plan management with Stripe billing — feature flags travel inside the token, eliminating the need for each app to query a billing API
- Consumption tracking — record arbitrary numeric metrics (requests, storage bytes, seats) from application back-ends using a
client_credentialsaccess token
What Auth Service is not
- A general-purpose reverse proxy or gateway — it does not terminate TLS on behalf of other services
- A directory server (LDAP/AD) — it stores users in PostgreSQL via Drizzle ORM
- A replacement for a full-featured commercial IAM platform — it targets small-to-medium self-hosted deployments
Stack
| Layer | Technology |
|---|---|
| Runtime | Node.js 22, TypeScript (ESM) |
| Web framework | Fastify 5 |
| Auth engine | BetterAuth 1.5 + @better-auth/oauth-provider |
| ORM | Drizzle ORM + postgres driver |
| Database | PostgreSQL 17 |
| Frontend | Vue 3 + Vite + Tailwind CSS v4 |
| Tests | Vitest + Supertest |
| Container | Docker (multi-stage build) |
Architecture overview
┌─────────────────────────────────────────────────────┐
│ auth-service │
│ │
│ Fastify 5 │
│ ├─ /api/auth/* → BetterAuth handler │
│ ├─ /api/admin/* → Admin REST API │
│ ├─ /api/consumption → Consumption tracking API │
│ ├─ /api/user/* → User-facing data API │
│ ├─ /api/webhooks/* → Stripe webhook receiver │
│ ├─ /login → Auth page (template / SPA) │
│ └─ /* → Vue 3 admin SPA │
│ │
│ BetterAuth plugins │
│ ├─ emailAndPassword │
│ ├─ twoFactor (TOTP) │
│ ├─ passkey (WebAuthn) │
│ ├─ admin (global roles) │
│ ├─ jwt (asymmetric signing) │
│ └─ oauthProvider (OAuth 2.1 / OIDC) │
└─────────────────────────────────────────────────────┘
│
▼ PostgreSQL 17
The oauthProvider plugin issues signed id_tokens. Custom claims (roles, permissions, features) are injected via the customIdTokenClaims hook in src/auth.ts, which delegates to getUserClaims() in src/services/claims.ts.