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_credentials access 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

LayerTechnology
RuntimeNode.js 22, TypeScript (ESM)
Web frameworkFastify 5
Auth engineBetterAuth 1.5 + @better-auth/oauth-provider
ORMDrizzle ORM + postgres driver
DatabasePostgreSQL 17
FrontendVue 3 + Vite + Tailwind CSS v4
TestsVitest + Supertest
ContainerDocker (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.

Copyright © 2026