ComplicatedAuth
Menu

Guides / Operations

Operate a Project.

Configure origins, administer service accounts and users, process paginated activity, and handle API failures safely.

Tenant roles

Role checks happen in the API on every console request; hiding a control in the console is not authorization. A Tenant always retains at least one active owner.

RoleTenant membersProjects and credentialsOAuth + Resource ServersProject UsersSupport Cases
OwnerManage, including ownersManageManageManage and supportManage
AdminManage non-ownersManageManageManage and supportManage
DeveloperReadManageManageManage and supportNone
SupportReadReadReadRead and revoke sessionsManage
ViewerReadReadReadReadNone

Tenant invitations

Owners and administrators create invitations with a required Idempotency-Key. ComplicatedAuth emails the one-time fragment-based acceptance link directly; its proof is never returned to the administrator or exposed by a list operation. Replaying the same creation request and key returns the same safe result for 24 hours without scheduling a second invitation. Acceptance consumes the proof atomically, verifies the invited email by possession, and establishes only a bootstrap session; first WebAuthn enrollment is still required.

Management sessions

Signup and invitation acceptance create a narrowly authorized bootstrap session. Ordinary control-plane operations require a strong session created or upgraded by user-verified WebAuthn. Each Tenant Member can list their own active sessions and assurance levels and revoke them individually. Inventory exposes identifiers and timestamps, never cookie values. Revoking the current session also clears its browser cookie; disabling a Tenant Member revokes every session they own.

Management authenticators

Tenant Members may keep at most ten named passkeys or attested security keys. Reads expose safe metadata only—never authenticator identifiers, public keys, counters, or ceremony state. Rename and removal use strong ETags. The final credential is protected from deletion, and removing another credential revokes every session except the one authorizing the removal. Password reset is the lost-all-authenticators recovery path and removes the whole credential inventory.

OAuth client and consent lifecycle

Owners, administrators, and developers manage OAuth Applications and their client secrets. Support and viewer roles may inspect registrations but never read or create credentials. Application updates require the latest strong ETag; a stale administrator receives 412 version_conflict instead of silently overwriting current redirects. Tenant Members approve access for themselves and can revoke their own grants under My account regardless of their administrative role.

Resource Server and delegated-scope lifecycle

Owners, administrators, and developers register Resource Servers, create immutable scope tokens, and assign scopes to OAuth Applications. Support and viewer roles may inspect but cannot mutate these resources. Resource Servers, scopes, and application grants require strong ETags for updates and deletion; creation is idempotent. Disabling or deleting any boundary revokes matching server-tracked tokens and increments the Resource Server policy version.

Origin configuration

Add exact browser origins, including scheme and port. HTTPS is required outside localhost. Keep at least one origin configured, and do not use wildcard matching. Changing RP ID after FIDO enrollment is blocked because existing credentials are scoped to that ID.

Service-account lifecycle

  1. Create one stable service account for each independently operated workload and grant exact scopes.
  2. Issue an expiring credential version and copy its one-time secret into a server-side secret manager.
  3. Rotate by issuing and deploying a replacement while the old credential remains active.
  4. Use audit activity, fingerprint, and last_used_at to confirm cutover.
  5. Revoke the old or suspected credential independently. Never share one account across unrelated workloads.

At most two active credential versions may overlap. Scope and status changes use the service account’s current ETag. See the service-account guide for the complete contract.

Project users

Provision and update users through the console or a service account with the corresponding project_users.* scope. Disabling a user blocks authentication; password replacement and explicit session revocation invalidate active sessions. The detail endpoint includes enrolled passkey identifiers and creation times.

Support Case operations

Owners, administrators, and support members operate the Tenant-wide inbox. Triage uses the case ETag, correspondence is append-only, and internal notes and external references never cross the Project service-credential boundary. Closing schedules a 365-day retention deadline; reopening clears it. See the Support Cases guide for retry, attachment, and state-transition rules.

Pagination

List operations return items and an optional opaque next_cursor. Pass it back unchanged as cursor. Do not parse or persist assumptions about its internal format. The default limit is 25 and the maximum is 100.

Error envelope

{
  "error": {
    "code": "invalid_session",
    "message": "session is invalid or expired",
    "request_id": "…",
    "details": {}
  }
}

Branch on HTTP status and error.code, not message text. Log request_id with your trace while excluding service credentials, passwords, WebAuthn payloads, selfies, and bearer references.

Retries and idempotency

Retry connection failures, timeouts, and transient server responses only when an operation documents retry semantics. For operations that accept Idempotency-Key, generate a high-entropy key per logical mutation, reuse it only with the byte-equivalent logical request, and retain the original result. ComplicatedAuth scopes the key to the authenticated principal and operation, rejects changed inputs, and replays a completed HTTP response. Do not add the header to an operation that does not publish it in OpenAPI.

Audit activity

Review Project activity after service-account, credential, user, session, origin, or Support Case changes. Tenant activity aggregates control-plane changes. Export or forward events before the platform's retention window if your compliance policy requires longer storage.

Background-job operations

The job queue is an internal implementation resource, not a customer API. Operators inspect payload-free summaries directly through the database-backed CLI:

go run ./cmd/jobctl list --status dead_lettered --limit 100
go run ./cmd/jobctl replay   --job 00000000-0000-0000-0000-000000000000   --actor [email protected]   --reason "dependency restored; incident INC-123"

Replay is accepted only for a dead-lettered job. It resets the attempt state transactionally and writes an immutable platform_operator_actions record containing actor, reason, action, target, and safe metadata. The CLI does not print job payloads. Investigate the dependency or data failure before replaying, and alert on queue age, abandoned leases, retry growth, and dead letters.

A deduplicated hourly maintenance job deletes expired transient records in bounded batches of 1,000 and reschedules itself. It covers idempotency records, rate buckets, login attempts, WebAuthn ceremonies, verification/reset proofs, ended sessions, OAuth requests/codes/tokens, expired invitations, delivered-email metadata, and old completed jobs. A saturated batch retries after one minute so cleanup makes progress without monopolizing the database.

Search guides, architecture, SDKs, and the REST API.