Skip to content

Better Auth — Central Authentication

Deploy Better Auth v1.5 as a shared authentication service on the Coolify server (159.195.68.41), replacing the custom magic-access server on the old server. All admin services on *.magicomniverse.online will be protected via Traefik forwardAuth with cross-subdomain SSO cookies.

Framework

Better Auth v1.5 + Express + TypeScript

Frontend

Vite + React + Tailwind (login/2FA pages)

Database

PostgreSQL (magic_auth on magic-postgres)

Repo

midego1/Magic-Auth (to be created)

ItemValue
URLhttps://auth.magicomniverse.online
Coolify Projecttools / production
StatusPlanned (reviewed by Codex, 9 critical fixes incorporated)
Replacesmagic-access (old server, port 3334)
Users19 existing users (4 admin, 2 dev, 13 client)
CriteriaBetter Authmagic-access (current)KeycloakAuthentik
LanguageTypeScriptNode.js (custom)JavaPython
Weight~5MB npm~Custom 1300 LOC~500MB Docker~800MB Docker
2FATOTP + Email OTP (plugin)WhatsApp + Email OTP (custom)Built-inBuilt-in
Device TrustBuilt-in (2FA plugin)Custom 64-char tokensBuilt-inBuilt-in
Multi-tenantOrganization pluginProject-based (custom)RealmsTenants
SessionsPostgreSQL-backedIn-memory (lost on restart)DatabaseDatabase
Cross-serviceShared subdomain cookiesIP whitelist + nginxOIDC/SAMLOIDC/SAML
MaintenanceActive (27.5k stars, v1.5.6)Hand-rolled, single developerEnterprise teamCommunity
Browser visits any *.magicomniverse.online
|
Traefik Proxy (v3.6.11)
|
forwardAuth middleware --> auth.magicomniverse.online/api/verify
| |
| Valid session cookie?
| / \
| YES NO
| | |
| 200 + headers 302 --> /login?redirect=...
| |
v |
Target Service (user logs in, cookie set
(portal, monitor, on .magicomniverse.online,
price-import, etc.) redirect back)
Cookie: better-auth.session_token
Domain: .magicomniverse.online <-- shared across ALL subdomains
HttpOnly: true | Secure: true | SameSite: Lax

One login covers all protected services. No per-app auth code needed.

ServiceCurrent AuthAfter
portal.magicomniverse.onlineNone (public)forwardAuth
monitor.magicomniverse.onlineNone (public)forwardAuth
price-import.magicomniverse.onlineBasic AuthforwardAuth
admin-*.magicomniverse.onlineMedusa loginforwardAuth + Medusa login
terminal.magicomniverse.onlineNoneforwardAuth (+ WS handshake validation)
flowbuilder.magicomniverse.onlineNoneforwardAuth
n8n*.magicomniverse.onlinen8n built-inforwardAuth (webhooks excluded)
pim.magicomniverse.onlineNoneforwardAuth
ServiceWhy
auth.magicomniverse.onlineThe auth service itself (would loop)
Storefronts (brinxx, default, etc.)Public customer-facing shops
Webhook paths (n8n /webhook/*)External integrations need access
Internal services (*.internal)Not publicly routable

Codex identified that Traefik forwardAuth doesn’t auto-redirect on 401. The /api/verify endpoint returns a 302 redirect to the login page for browser requests, and 401 JSON for API/XHR requests (detected via Accept header).

Static API key (BREAK_GLASS_KEY env var) that bypasses auth entirely. If the auth service crashes, admins can still access services by passing X-Break-Glass header.

Services with public endpoints (n8n webhooks, health checks) use split Traefik routers: one public (no auth), one protected (with auth), differentiated by path prefix.

Existing bcryptjs hashes ($2a$ prefix, 10 rounds) must be verified compatible with Better Auth’s bcrypt implementation before building the migration script. This is a Day 0 pre-build checkpoint.

The auth service container is only reachable via the Coolify Docker network (Traefik proxy). No direct port mapping to the host.

  1. Day 0: Pre-Build Verification

    • Verify bcrypt hash compatibility
    • Test Traefik forwardAuth 302 behavior
    • Test cross-subdomain cookies in browser
    • Confirm PostgreSQL + SMTP connectivity from Coolify
  2. Phase 1: Core Auth Service

    • Create midego1/Magic-Auth repo
    • Build Express + Better Auth backend
    • Build Vite React login/2FA frontend
    • Deploy on Coolify as auth.magicomniverse.online
    • Run Better Auth DB migrations
  3. Phase 2: User Migration

    • Run migration script (19 users from magic_access.users)
    • Verify admin login + 2FA enrollment
    • Set up audit logging
  4. Phase 3: Service Protection (one at a time)

    • Pilot on a disposable test service first
    • Then: price-import (remove Basic Auth)
    • Then: portal, monitor, terminal, flowbuilder, pim
    • Then: admin backends, n8n instances
    • Each with per-path exceptions as needed
  5. Phase 4: Cleanup

    • Remove Basic Auth from price-import code
    • Update devdocs
    • Update CLAUDE.md
LayerProtection
Session cookiesHttpOnly, Secure, SameSite=Lax, domain-scoped
CSRFSameSite + Better Auth built-in CSRF tokens
Brute forceRate limiting (5 attempts / 15 min)
2FATOTP (authenticator app) + Email OTP fallback
Trusted devices30-day device trust via 2FA plugin
Header spoofingTraefik strips client X-Auth-* headers
Open redirectRedirect URLs validated against trustedOrigins
Audit trailAll login/2FA/admin events logged
Break-glassEmergency API key bypass for admin lockout
  • WhatsApp OTP — using TOTP instead (no Meta API dependency)
  • IP whitelisting — replaced by session-based auth
  • Password expiry/history — can add via Better Auth hooks in v2
  • RBAC/authorization — v1 is auth-only, v2 adds role-based access
  • HA/multi-instance — overkill for 19 users
  • OIDC provider — services use forwardAuth, not OIDC
ReviewStatusFindings
Codex ReviewDONE30+ findings, 9 critical fixes incorporated
Eng ReviewPendingRecommended before implementation
CEO Review
Design Review
  1. forwardAuth 401 doesn’t redirect — added 302 redirect with Accept header detection
  2. No break-glass admin path — added emergency API key bypass
  3. Password hash compatibility unproven — added Day 0 verification step
  4. Webhooks break with blanket auth — added per-path Traefik routing
  5. WebSocket auth for terminal — validate on WS handshake, not forwardAuth
  6. Logout across subdomains missing — clear domain-scoped cookie
  7. XHR calls can’t follow 302 — return 401 JSON for API requests
  8. Audit logging missing — added login/2FA/admin event logging
  9. Auth service network isolation — verify container only reachable via Docker network
  1. Remove magic-auth middleware from Traefik labels on affected service (per-service)
  2. Re-add previous auth (Basic Auth for price-import, etc.)
  3. Use break-glass key during incidents
  4. Auth service can be stopped without affecting other services

ForwardAuth is per-service. Removing it from one service’s labels instantly removes auth for that service only. No global config to break.