Authentication
How identity works - Better Auth behind an Effect service, sessions, Google OAuth, WorkOS enterprise SSO, and the session helpers server code uses.
Authentication answers the question “who is calling?”. Africa OS uses Better Auth for identity under the hood, but application code never touches it. Everything goes through AuthService, an Effect service in @africaos/auth.
The layering
The key rule: provider.ts is the only file in the repository that imports better-auth. Everything else programs against the small, typed AuthService surface. This keeps the identity provider swappable and gives server functions Effect-native errors.
What AuthService offers
AuthService is an Effect Context.Service (platform/auth/src/service.ts). Its methods take the incoming request Headers and return the parsed result plus the auth Response (so the caller can propagate the Set-Cookie headers):
| Method | Purpose |
|---|---|
signIn |
Email + password sign-in. |
signUp |
Email + password sign-up. |
signOut |
End the session, returning the response carrying the clearing cookies. |
getSession |
Resolve the active session, as Option.none() when unauthenticated. |
signInWithGoogle |
Start a Google OAuth handshake, returning the consent URL. |
completeGoogleSignIn |
Exchange the OAuth callback code/state for a session. |
signInEnterpriseMember |
Issue a session for a WorkOS-verified enterprise member. |
Every method returns typed errors instead of throwing ad hoc: InvalidCredentials, EmailAlreadyInUse, OAuthUnavailable, and AuthFailure.
Sign-in errors are typed
AuthService maps Better Auth responses onto typed failures:
- A 401 from the provider becomes
InvalidCredentials. - A 422 with an
EMAIL_ALREADY_IN_USEorUSER_ALREADY_EXISTS_USE_ANOTHER_EMAILcode becomesEmailAlreadyInUse. - OAuth handshakes succeed as redirects (3xx with a
Locationheader), so success is tested by status range, notresponse.ok. - Anything else becomes
AuthFailurewrapping the cause.
This is why server functions can fold failures into serializable results without string-matching error messages.
Google OAuth
Google sign-in has two halves:
- Start -
signInWithGoogle(headers, callbackURL)returns the consent URL to send the browser to, alongside the authResponsewhose cookies carry the OAuth state across the redirect. - Complete -
completeGoogleSignIn(headers, { code, state })exchanges the callback parameters for a session and returns the authResponse.
Both fail with OAuthUnavailable when Google is not configured (no GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET), so the feature degrades gracefully instead of throwing at runtime.
WorkOS enterprise SSO
WorkOS handles enterprise single sign-on. signInEnterpriseMember issues a Better Auth session for a member who has already been verified by WorkOS - the service takes the verified profileId and connectionId rather than re-authenticating. The WorkOS provider lives in platform/auth/src/workos/service.ts.
The session helpers
platform/auth/src/session.ts offers the two helpers server code uses most:
// Optionally-resolved user; None when unauthenticated.
const user = yield* resolveCurrentUser(headers);
// Hard requirement; fails with Unauthenticated.
const user = yield* requireCurrentUser(headers);
Both run as Effect programs against AuthService, so they work anywhere a service is available. The request runtime uses requireCurrentUser during assembly - a request without a session fails before any handler logic runs.
sessionCookies(response) extracts the Set-Cookie values from an auth response, which callers attach to their own response to persist the session.
Where the sessions live
Better Auth manages its own tables in the public schema (user, session, account, verification), created by migration 0001_identity.sql. The platform never queries these directly - it goes through AuthService.
Authentication is not authorization
Authentication only establishes who the caller is. Whether the caller may perform an action is the job of permissions, resolved per organization by the request context.
Next steps
- Request context - how the identity becomes a full runtime.
- Authentication - this guide, the full service surface and the provider boundary.