CrydenSync
HTTP API

HTTP API — Overview

The `api` repository is a self-hosted HTTP wrapper around the CrydenSync engine — not a hosted, multi-tenant service.

The api repository is a self-hosted HTTP wrapper around the CrydenSync engine. It is not a hosted, multi-tenant service — every deployment is your own instance, connected to your own database, serving only your own application.

Who this is for

  • Developers whose application is not written in Go, and therefore cannot import the cryden engine directly — Python, Node, Ruby, PHP, anything that can make an HTTP request.
  • Go developers who want a REST interface anyway (for a frontend SPA, for example) rather than embedding the engine in their own backend.

Architecture in one sentence

Every HTTP handler is a thin translation layer: parse the request, call the corresponding cryden.* engine function, map the result or error to an HTTP response. No authentication logic lives in this repository — it all lives in the engine. Anything this repo does add on top (console operator roles, per-user metadata, delivery logs, admin settings storage) is deliberately kept in its own tables, separate from cryden's own schema — see design-decisions.md for why the engine itself never grows a role or permission concept.

What's covered end to end

  • Core auth: signup, login, refresh, logout, sessions, change password, delete account, email change
  • OAuth login/signup: Google, GitHub, Microsoft, Discord, GitLab, and Apple
  • Second factors, all completing through one shared paused-login shape: TOTP, passkeys (WebAuthn), recovery codes
  • Magic-link (passwordless) login
  • Named sessions (device and, if a geolocator is configured, location)
  • API keys for machine-to-machine auth
  • An admin console surface, behind its own operator role, covering: user search and inspection, MFA/passkey adoption stats, password-hash migration progress, OAuth provider health, webhook and cloud-logging delivery logs, the weekly digest with scheduling and history, the support-ticket assistant, the config tuning advisor, anomaly review, and settings for the LLM provider and read-only database role the Ask-AI widget uses

See Endpoints for the full public/user-facing reference and Admin Console for everything behind the operator role.

Base URL and versioning

All endpoints are under a versioned prefix:

https://your-deployment.example.com/v1/...

The /v1 prefix exists so that a future breaking change to the API contract can be introduced as /v2 without breaking existing consumers still using /v1 — the same reasoning that governs the engine's own /v2 Go module path. One response shape did change within /v1 already: GET /v1/sessions gained label/device/location fields when named sessions shipped — see Endpoints.

Interactive docs, out of the box

Every running deployment serves its own interactive API reference, no separate hosting, no build step:

GET /v1/docs               — a Swagger UI page
GET /v1/docs/openapi.yaml  — the spec itself

Open http://localhost:8080/v1/docs (or your deployment's own URL) right after starting the server and it's already there. Both routes are public — the spec documents every endpoint's own auth requirement, so the docs page carrying none is consistent with everything it describes — and both are identical regardless of whether the deployment runs on Postgres or SQLite.

The Swagger UI assets are compiled into the binary itself (no CDN fetch at request time), which matters for the same reason the migrations are embedded rather than read from disk: a self-hosted auth API reaching out to a third party just to render its own documentation page would be exactly the kind of outbound dependency this project avoids everywhere else.

Response envelope

Every response is one of exactly two shapes.

Success:

{ "data": { "...": "..." } }

Error:

{ "error": { "code": "invalid_credentials", "message": "invalid email or password" } }

code is a stable string, safe to branch on programmatically. message is a human-readable string and must never be parsed by client code — its exact wording is not part of the contract and may change. See errors.md for the complete list of codes.

Authentication

Authenticated endpoints require an Authorization: Bearer <access_token> header. The access token is the short-lived JWT returned by /v1/login or /v1/refresh. Admin console endpoints require the same header, but the token must additionally carry a role: "admin" claim — see Admin Console for how that's granted.

CORS

The API requires an explicit, non-wildcard list of allowed origins, configured via the CORS_ORIGINS environment variable. There is no permissive default — an API that hands out authentication tokens should never allow requests from an unknown origin by default.

Rate limiting

Two independent layers apply:

  • The engine's own per-user rate limiting on login and signup specifically (in-memory by default, or Redis-backed for multi-instance deployments).
  • The API's own coarser, per-IP rate limiting across the entire surface (see rate-limiting.md).

See also

  • endpoints.md — every public/user-facing endpoint, request/response shape, with copyable curl commands
  • oauth.md — the OAuth flow across all six providers, including Apple's differences
  • admin.md — the admin console surface, behind the operator role
  • authentication.md — the auth flow in detail, including token refresh, reuse detection, and the second-factor pause flow
  • errors.md — the complete error code reference
  • rate-limiting.md — both rate limiting layers explained