Getting started

Introduction

What auth-service is, when to use it, and how it fits into a CIRCLE Cyber deployment.

Auth Service is a self-hosted OAuth 2.1 / OIDC identity provider built on BetterAuth v1.7. It acts as the central authentication and authorisation hub for a fleet of backend services and frontend applications.

What it provides

  • OAuth 2.1 authorization server — authorization code + PKCE, client credentials, token refresh, token introspection, JWKS endpoint, and OIDC discovery.
  • Multi-application model — each registered application is an independent OAuth 2.0 client with its own RBAC model, subscription plans, and access policy.
  • Per-app RBAC — roles and permissions are defined per application and injected as roles / permissions claims in JWT access tokens when the roles / permissions scope is requested.
  • MFA — TOTP (authenticator apps) with backup codes, enforced per application or per user at token-issuance time. The WebAuthn passkey endpoints (@better-auth/passkey) are enabled on the server; the account page does not offer passkey enrolment yet.
  • Subscription plans — plans carry a features JSON object that is surfaced as a features claim in tokens when the features scope is requested. Optional Stripe integration for billing.
  • Consumption tracking — a lightweight accounting layer for recording and querying numeric counters (API calls, credits, storage) per user per application. Accepts either a client_credentials access token bound to one application or an admin session.
  • Credit wallet — one prepaid euro balance per user, shared by every application and by the LiteLLM gateway: top-up with Stripe or by an administrator, spend reported per call, accounting journal.
  • Organizations — multi-tenant support; users belong to organizations and can carry an org_id claim in their access tokens.
  • Social login — Google and GitHub, with a per-application allow-list.
  • Login history — tracks every successful login with IP, user-agent, and application context.
  • Custom templates — override the login, register, verify-email, email-verified, select-org, two-factor, device and error pages per application via TEMPLATES_DIR, and the transactional emails globally or per application (when the e-mail has an application context).
  • Dynamic branding — APP_NAME + APP_LOGO_URL are served via /api/app-config and drive the frontend UI.
  • Admin dashboard — Vue 3 SPA with active-users stats, login charts, session management, and user detail views.
  • Embedded admin SPA — a Vue 3 frontend served by the service itself (sign-in at /auth) with Dashboard, Users, Organizations, Applications (roles, permissions and plans are managed per application), Wallets, Accounting and Configuration pages.

When to use auth-service

Auth Service is the right choice when you need:

  • A private OAuth 2.1 / OIDC provider with no dependency on a cloud identity service.
  • Fine-grained per-application access control that travels inside tokens, so downstream services do not need to query the auth provider on every request.
  • A single place to manage users across multiple internal applications (REST APIs, MCP servers, frontends) with different role models.
  • MCP server integration — any MCP client can authenticate via OAuth 2.1 Authorization Code + PKCE and receive a JWT access token with roles/permissions/feature claims.

It is not a drop-in replacement for a full IAM platform such as Keycloak or Okta: there is no SAML and no LDAP / Active Directory federation. It prioritises simplicity and tight integration with the CIRCLE Cyber stack over broad protocol coverage. To move an existing application over, see the migration guides for Okta, Auth0 and Keycloak, and the compatibility profiles that make an instance behave like the provider it replaces.

How it fits in

Browser / CLI / MCP client
        │
        │  OAuth 2.1 authorization code + PKCE
        ▼
┌─────────────────────┐
│    auth-service     │  ← this project
│  (BetterAuth core)  │
└────────┬────────────┘
         │  JWT access token (roles, permissions, features, org_id)
         ▼
┌─────────────────────┐
│  backend service    │  e.g. IOServer + IOServer-OIDC middleware
│  (resource server)  │  verifies token against JWKS, no secret required
└─────────────────────┘

The backend service uses IOServer OIDC (or any JWKS-capable middleware) to verify tokens issued by auth-service. No shared secret is required — validation is done with the public key set published at /api/auth/jwks.

Stack

LayerTechnology
RuntimeNode.js 22, TypeScript (ESM)
Package managerpnpm 10
Web frameworkFastify 5
Auth engineBetterAuth 1.7 + @better-auth/oauth-provider
JWT signingjwt() plugin (asymmetric; EdDSA / Ed25519 by default, RS256 selectable with JWT_PRIMARY_ALG or a compatibility profile; keys rotated monthly)
Passkey / YubiKey@better-auth/passkey
TOTP (Auth app)twoFactor() from better-auth/plugins
Admin / global rolesadmin() + role() from better-auth/plugins
Organizationsorganization() from better-auth/plugins
ORMDrizzle ORM + postgres driver
DatabasePostgreSQL 17
FrontendVue 3 + Vite 8 + Tailwind CSS v4
TestingVitest + Supertest + Playwright (E2E) + testcontainers
ContainerDocker (multi-stage, Node 22 Alpine)

A tour of the admin interface

All captures use demo data.

Users — roles, MFA status, applications and last login.

Applications — OAuth clients; infrastructure applications are hidden unless asked for.

Configuration — sign-in providers, MFA adoption and billing status.

Account security — every user manages their own sessions and second factor.

Wallets — credit held, pricing of LLM usage, spend and top consumers.

Accounting journal — every top-up, credit adjustment and plan change, with who made it.

Copyright © 2026