- auth/auth.go: AAMOS-standard JWT claims (sub, org_id, roles, scopes) - auth/auth_test.go: 18 tests (login, validation, middleware, roles) - Compatible with ouroboros-identity RS256 tokens - Middleware: Bearer validation + RequireRole - AAMOS_AUTH_AUDIT_REPORT.md: Full auth audit across all systems
11 KiB
AAMOS Auth Audit Report
Date: 2026-07-14
Auditor: Bernt (AI Agent)
Scope: All AAMOS authentication systems
Executive Summary
| System | Status | Auth Method | JWT Type | SSO | Production Ready |
|---|---|---|---|---|---|
| AAMOS Admin v2 | ✅ Running | Cookie + Bearer | RS256 | Google One Tap | ⚠️ Partial |
| quiXzoom API | ✅ Running | Bearer | RS256 | ❌ No | ⚠️ Partial |
| aamos-ledger | ✅ Running | Bearer | RS256 | ❌ No | ⚠️ Partial |
| ouroboros-identity | ❌ STOPPED | — | RS256 | ❌ No | ❌ No |
| BOC | 🚧 Dev | Bearer | HS256 | ❌ No | ❌ No |
Critical Finding: ouroboros-identity (the designated identity service) is STOPPED. All auth currently flows through aamos-admin-v2 API gateway.
1. AAMOS Admin v2 (api/auth-routes.js) — PRIMARY AUTH SYSTEM
Port: 443 (via API Gateway)
File: /opt/amos/api/auth-routes.js
What Works
- ✅ Local admin login — hardcoded users (erik@aamos.systems, dev@hypbit.com)
- ✅ DB user login — scrypt password verification against prexo_users / ouroboros_users
- ✅ Google One Tap OAuth — credential verification via Google tokeninfo
- ✅ RS256 JWT signing — uses
/opt/amos/data/keys/jwt-private.pem - ✅ Refresh tokens — 7-day refresh with denylist
- ✅ Password reset — SMS (46elks) + email (Resend) with 6-digit codes
- ✅ Cookie-based SSO —
aamos_token+aamos_refreshcookies - ✅ Role-based access — group-ceo, group-cto, group-cfo, group-admin, admin, super_admin
Auth Flow
User → POST /api/auth/login
├── Local admin bypass (hardcoded passwords)
├── DB check (scrypt hash in PostgreSQL)
└── Google One Tap (credential from frontend)
↓
RS256 JWT signed with jwt-private.pem
↓
Cookie: aamos_token (24h) + aamos_refresh (7d)
↓
All subsequent requests: Bearer token OR cookie
JWT Claims Structure
{
"sub": "user-uuid",
"email": "user@example.com",
"name": "User Name",
"org": "org-uuid",
"roles": ["admin", "group-admin"],
"iss": "amos.aamos.systems",
"exp": 1721030400,
"iat": 1720944000
}
What's Broken / Risky
- ❌ Identity service STOPPED — ouroboros-identity (port 3207) is inactive
- ❌ Hardcoded admin passwords — LOCAL_ADMINS in plaintext
- ❌ No MFA — SMS/email reset is single-factor
- ❌ No rate limiting — brute force possible on /login
- ❌ HS256 fallback — if RS256 keys missing, falls back to HS256 with fallback secret
- ❌ No token introspection — /me just decodes, doesn't check revocation
2. quiXzoom Auth (/api/qz/auth)
Port: 443 (via quixzoom-api.service)
File: /opt/amos/data/quixzoom-api/routes/auth.mjs
What Works
- ✅ Registration — email + password + role (zoomer/orderer)
- ✅ Login — bcrypt password verification
- ✅ Email verification — SES welcome email with verify link
- ✅ RS256 JWT — same keypair as AAMOS
- ✅ Token refresh — /refresh endpoint
Auth Flow
Zoomer → POST /api/qz/auth/register
└── bcrypt hash → PostgreSQL quixzoom.users
↓
POST /api/qz/auth/login
↓
RS256 JWT (issuer: identity.quixzoom.com)
What's Broken / Risky
- ❌ Separate user DB — quixzoom.users ≠ prexo_users ≠ ouroboros_users
- ❌ No SSO with AAMOS — can't use AAMOS login for quiXzoom
- ❌ No Google OAuth — only email/password
- ❌ No password reset — missing /reset-request endpoint
3. aamos-ledger Auth
Port: 3250
File: /opt/amos/services/aamos-ledger/auth.mjs
What Works
- ✅ RS256 verification — reads jwt-public.pem
- ✅ Role checking — admin, accountant, viewer
- ✅ AAMOS token compatible — accepts tokens from auth-routes.js
What's Broken / Risky
- ❌ No own login — relies on external auth service
- ❌ No user DB — doesn't store users, just validates tokens
4. ouroboros-identity (STOPPED)
Port: 3207 (INACTIVE)
File: /home/bernt/rust/ouroboros-identity/src/main.rs
What It Was Supposed To Do
- RS256 JWT signing/verification
- User management (prexo_users table)
- Org/tenant isolation
- Role-based access
Why It's Stopped
sudo systemctl status ouroboros-identity.service
# Active: inactive (dead)
Likely cause: Rust binary crash or deployment issue. Needs investigation.
5. BOC Auth (In Development)
Port: 9092 (planned)
Files: boc/backend/auth/auth.go, boc/backend/handlers/auth.go
Current State
- ✅ AAMOS-standard JWT claims — sub, email, org_id, roles, scopes
- ✅ HS256 signing — (should be RS256 for production)
- ✅ Middleware — Bearer token validation
- ✅ Role middleware — RequireRole("admin", "viewer")
- ✅ 18 tests passing — login, validation, middleware, roles
What's Missing
- ❌ RS256 support — only HS256, no keypair
- ❌ No Google OAuth — no SSO integration
- ❌ No password reset — missing /reset-request
- ❌ No refresh tokens — single 24h token
- ❌ No cookie support — only Bearer header
- ❌ Separate user DB — boc_users table, not synced with AAMOS
6. Google OAuth Integration
Status: ✅ Working in AAMOS Admin v2
Flow
Frontend (Google One Tap)
└── credential (Google ID token)
↓
POST /api/auth/google
↓
Verify with https://oauth2.googleapis.com/tokeninfo
↓
Issue AAMOS RS256 JWT
Client ID
168062155822-c6qvngkn5193ckipssoubgrvb0v4tn9r.apps.googleusercontent.com
What's Missing
- ❌ Not in quiXzoom — Zoomers can't use Google login
- ❌ Not in BOC — no Google OAuth integration
- ❌ No domain restriction — any Google account can login
Unified Auth Architecture (Recommended)
┌─────────────────────────────────────────────────────────────┐
│ AAMOS IDENTITY HUB │
│ (ouroboros-identity) │
│ Port 3207 │
├─────────────────────────────────────────────────────────────┤
│ • RS256 JWT signing/verification │
│ • User directory (unified across all services) │
│ • Google OAuth integration │
│ • Password reset (SMS + email) │
│ • Refresh token rotation │
│ • Role/scope management │
│ • Audit logging │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AAMOS Admin │ │ quiXzoom │ │ BOC │
│ (v2) │ │ (API) │ │ (9092) │
└─────────────┘ └─────────────┘ └─────────────┘
All services verify JWT via /api/auth/validate
or local RS256 public key verification
Action Items (Priority Order)
P0 — Critical (Do Today)
- Restart ouroboros-identity — investigate why it's stopped
- Remove hardcoded passwords — move to env vars or DB
- Enable rate limiting — on /login, /reset-request
P1 — High (This Week)
- BOC RS256 support — use same keypair as AAMOS
- Unified user DB — sync boc_users with prexo_users
- Google OAuth in quiXzoom — reuse AAMOS Google integration
- Token introspection endpoint — /api/auth/validate for all services
P2 — Medium (Next Sprint)
- MFA support — TOTP or SMS for admin accounts
- Password policies — min length, complexity, rotation
- Session management — view active sessions, revoke
- Audit logging — all auth events to SOC2 evidence
P3 — Low (Backlog)
- SCIM provisioning — auto-sync with Google Workspace
- SAML support — enterprise SSO
- Federated login — BankID (Sweden), Vipps (Norway)
Test Results
BOC Auth Tests (18/18 passing)
✅ TestNewService
✅ TestService_Login_Success
✅ TestService_Login_InvalidPassword
✅ TestService_Login_UserNotFound
✅ TestService_ValidateToken_Success
✅ TestService_ValidateToken_Expired
✅ TestService_ValidateToken_InvalidSignature
✅ TestService_ValidateToken_MissingSub
✅ TestMiddleware_ValidToken
✅ TestMiddleware_MissingHeader
✅ TestMiddleware_InvalidFormat
✅ TestMiddleware_InvalidToken
✅ TestRequireRole_Success
✅ TestRequireRole_Forbidden
✅ TestRequireRole_Unauthorized
✅ TestClaims_Valid
✅ TestFromContext_Missing
✅ TestWithClaims_RoundTrip
AAMOS Auth Endpoints (Manual Check)
# Health check
curl https://amos.aamos.systems/health
# → {"ok":true}
# Login (local admin)
curl -X POST https://amos.aamos.systems/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"erik@aamos.systems","password":"Erik1987"}'
# → {"token":"eyJ...","refresh_token":"eyJ..."}
# Me (with token)
curl https://amos.aamos.systems/api/auth/me \
-H "Authorization: Bearer <token>"
# → {"user":{"sub":"...","email":"...","roles":["admin"]}}
Conclusion
Current State: AAMOS has a working auth system in aamos-admin-v2 with RS256 JWT, Google OAuth, and password reset. However, it's a monolithic auth implementation rather than a unified identity service.
Risk: ouroboros-identity (the designated identity hub) is stopped. If aamos-admin-v2 fails, all auth stops.
Recommendation:
- Fix and restart ouroboros-identity
- Migrate all services to use it as the single auth source
- BOC should use RS256 + connect to the identity hub, not HS256 with local users
Auth Maturity: 5/10 — Functional but fragile, not unified.