Introduction

Camel Accounts

The shared SSO / OAuth 2.0 + OIDC identity provider for the CamelTech ecosystem (Bajeti, Simamia, MailAfrica, Ngamia, …).

Camel Accounts lets users create one account and use it across every CamelTech app. Client apps never see or store passwords — they redirect the user to Camel Accounts, get back an authorization code, exchange it for tokens, and receive cryptographically signed JWTs that prove who the user is.

First login = signup. Your app needs no registration screen and no password table. When a user completes the OAuth flow for the first time, their account already exists.

What it provides

CapabilityDetails
OAuth 2.0 Authorization Code flowPKCE required, S256 only
OIDCDiscovery document, JWKS, userinfo endpoint
Cross-app SSOLog in once in the browser, every other CamelTech app skips login
Password authEmail or phone + password (argon2id)
PasskeysWebAuthn/FIDO2 — full passwordless login that replaces password AND MFA
Social loginGoogle + GitHub with strict verified-email linking rules
MFATOTP (authenticator apps), enforced at every password login once enabled
VerificationEmail & phone via 6-digit OTP
Session managementUsers see and revoke their active sessions from the Cockpit
Developer consoleSelf-service projects, OAuth clients, one-time secrets, branding, audit logs

Base URLs

EnvironmentIssuer
Productionhttps://accounts.camelcreatives.com
Local developmenthttp://localhost:8080

Every endpoint in these docs is relative to the issuer. The discovery document at /.well-known/openid-configuration publishes all OAuth endpoints so standards-compliant libraries can auto-configure.

How it fits together

┌──────────────┐         ┌───────────────────────┐        ┌────────────────┐
│   Your App   │         │      Camel Accounts    │        │  Your Backend  │
│  (frontend)  │         │      (identity)        │        │   (resource)   │
└──────┬───────┘         └───────────┬──────────┘        └────────┬───────┘
       │                             │                            │
       │ 1. Redirect to /oauth/authorize                          │
       ├────────────────────────────>│                            │
       │                             │                            │
       │ 2. User signs in (password / passkey / social) + consent │
       │<───────────────────────────>│                            │
       │                             │                            │
       │ 3. 302 → your redirect_uri?code=…&state=…                │
       │<────────────────────────────┤                            │
       │                             │                            │
       │ 4. POST /oauth/token (code + code_verifier)              │
       ├────────────────────────────>│                            │
       │ 5. access_token + refresh_token                          │
       │<────────────────────────────┤                            │
       │                             │                            │
       │ 6. Call your backend with Bearer access_token            │
       ├─────────────────────────────────────────────────────────>│
       │                             │          7. Verify JWT against JWKS
       │                             │             (local, no network call)
  1. Your app redirects the user to /oauth/authorize with a PKCE challenge.
  2. Camel Accounts handles sign-in (password, passkey, or social) and consent on its own UI.
  3. It redirects back to your exact registered redirect_uri with a single-use code.
  4. Your app exchanges the code (+ PKCE verifier) at /oauth/token.
  5. You receive an RS256-signed access token (15 min) and a rotating refresh token (30 days).
  6. You call your backend with the access token; your backend verifies it locally against /oauth/jwks.
  7. Your backend creates or looks up its local user row by the sub claim (the Camel Accounts user UUID).

Three ways to sign in

All of these happen on Camel Accounts' own screens — your app only ever sees the redirect back with a code:

PASSWORD : identifier + password ──(TOTP if MFA enabled)──► session cookie
PASSKEY  : WebAuthn assertion ────────────────────────────► session cookie  (replaces password AND MFA)
SOCIAL   : Google/GitHub code ──(verified-email rule)─────► session cookie

Every login lands in the user's security activity feed (GET /auth/security-events) and can trigger alert emails.

Where to go next

First-party clients

These clients are seeded into the production database as reference registrations:

Client IDAppPlatformTypeRedirect URI
bajeti-androidBajetiAndroidpublicbajeti://oauth/callback
bajeti-webBajetiWebpublichttps://bajeti.cameltech.co/callback
simamia-androidSimamiaAndroidpublicsimamia://oauth/callback
simamia-webSimamiaWebpublichttps://simamia.cameltech.co/callback

New apps register their own clients through the Developer Console.