Status
v0.2 — JSON session endpoints. The full SPEC-055 §D contract — login, session (whoami), refresh, logout, signup, password-reset/{request,confirm} — is implemented under /api/client_auth/* over core AuthService, alongside the v0.1 Google/Apple OAuth port, the issueSession() seam, cookie/body transports, and the core-auth user store.
Next: the better-auth verifier engine (feature-gated; drawn from real product need — OTP / passkeys / device flow) and an integration-test harness (ephemeral host app in CI) are planned but not yet part of this repo — unit tests cover the verifier/store/transport logic.
Install
npm install @fullstackhouse/open-mercato-client-auth
# peer deps: @open-mercato/core, @open-mercato/shared, @mikro-orm/* (v7), next, zod
Register the module in your app's src/modules.ts:
const modules = [
// ...core modules...
{ id: 'client_auth', from: '@fullstackhouse/open-mercato-client-auth' },
]
The package ships the compiled module tree at dist/modules/client_auth/, which is where the Open Mercato CLI resolves package-backed modules from. Then run yarn generate (or mercato generate) and apply migrations.
Endpoints
Session (email/password)
| Endpoint | Purpose |
|---|
POST /api/client_auth/login | { email, password } → verifies credentials, issues a session. Responds { ok, token, refreshToken, expiresAt, user } and sets cookies. |
GET /api/client_auth/session | Whoami. Reads the cookie or bearer token → { user, expiresAt }; 401 when unauthenticated. |
POST /api/client_auth/refresh | session_token cookie or { refreshToken } → a fresh access JWT ({ ok, token, expiresAt, user } + cookie), reusing the same refresh token. 401 (+ cleared cookies) when the refresh token is invalid/expired. |
POST /api/client_auth/logout | Revokes the session row (from the session_token cookie or { refreshToken }) and clears cookies. |
POST /api/client_auth/signup | { email, password, name? } → creates a confirmed user in the default tenant with the base role, then issues a session (201). 409 when the email is taken; 403 when signup is disabled. |
POST /api/client_auth/password-reset/request | { email, redirectTo? } → always { ok: true } (anti-enumeration). When the email exists, emits client_auth.password_reset.requested carrying the reset token so the host sends the email. |
POST /api/client_auth/password-reset/confirm | { token, newPassword } → resets the password (core revokes all of the user's sessions). 400 on an invalid/expired token. |
expiresAt is the access-token (8h) expiry — what clients use to schedule a preemptive refresh; the refresh token lives REFRESH_TOKEN_DAYS (30d).
Password-reset email is the host's job. The package creates the core PasswordReset token and emits client_auth.password_reset.requested ({ userId, email, token, redirectTo, tenantId }). Subscribe to it and send the email via your notifications stack with a link to your frontend's reset-password screen. The package intentionally owns no email templates.
OAuth (Google / Apple)
| Endpoint | Purpose |
|---|
POST /api/client_auth/oauth/google/init | Start Google sign-in (returns the authorization URL). Body: `{ platform: 'web'\ | 'mobile', redirect? }` |