Normative protocol source: arkret-spec v1
After cloning, enable the project's pre-commit hooks:
git config core.hooksPath .githooksThe hook runs cargo fmt --all -- --check and cargo clippy --no-deps -- -D warnings on staged Rust changes. If .githooks/pre-commit is missing on a
branch, copy it from
arkret-rust-sdk and
adapt the package list to coauth's workspace.
DO NOT commit secrets. Files like
config.local.*, KeyStore master-key files,*.log, and unencrypted private keys are gitignored and must stay local. Useconfig.example.yamlas a template and source real values from environment variables or mounted secret files. A CIgitleaksjob (see.github/workflows/ci.yaml) fails the build if anything that looks like a credential lands in a tracked path.
Local development follows Coland's repository layout: all file-backed runtime
state lives below the gitignored .local/ directory. The encrypted KeyStore
and its master key are separate files; neither is source configuration.
coauth is the Station's internal authentication and account-management
component. It provides OIDC/OAuth login, account lifecycle management,
short-lived session grants, policy hooks, notifications, and an admin API.
Clients use the Account Authority entry published by their Station; a
separate coauth process does not create an Arkret service role or peer
discovery target. Station-local identity is the complete
AccountId {principal_id, station_id}.
coauth is not a DID registry. It proves who authenticated to which local
account, device, and session, then publishes that state to Stations
and admin tooling. DID documents, key logs, and registry receipts belong to
delegated/public DID resolver services.
Sessions, capabilities, and admin scopes attach to a Realm (the security boundary). Navigation containers — Space in the new vocabulary — sit inside a Realm and inherit its auth context.
- Realm: membership, capability, E2EE, federation are governed here.
- Space: board, list, section, or calendar bucket inside a Realm.
The deployment-level trust_domain config knob is
arkret.trust_domain in config.yaml:
arkret:
trust_domain: ak:trust_domain:coland-prod.euThe value MUST match ak:trust_domain:<scope> where <scope> is
[a-z0-9._:-]{1,128} and starts with [a-z0-9]. coauth validates it
on load via ArkretConfig::validate_trust_domain (mirrors the SDK's
TrustDomainId acceptance rules) and injects it into the Realm
policy + /_arkret/describe document via coland's config API.
The trust_domain value binds peer and recovery authorization
transcripts to this deployment. Rotate it only with coordinated expiry
of in-flight proofs and sessions issued under the prior value.
The canonical wire behavior lives in the v1 spec artifacts and prose under
../arkret-spec/spec/v1/.
- 3PID OOB invite has two wire modes. Either
offline_token(token_commitment+token_salt_id+token_entropy_bits ≥ 128, default) orlookup(lookup_table_ref+pepper_id, 3-strike invalidation). Plaintext 3PIDs are no longer carried on the wire. Both modes share the 5-terminal-state machine (claimed/send_failed/revoked_by_capability_loss/revoked_by_inviter_left/invalidated_by_rate_limit); salt / pepper are zeroized within 24h. - identity_link is Realm-scoped — encrypted payload now binds
realm_id+trust_domain.
Per-project task lists are maintained outside this repository. Protocol
work that affects wire shape is tracked in ../arkret-spec/spec/v1/.
inksonacts as a public/native Arkret client and consumes OIDC tokens.- Stations such as
colandconsume session grants and account metadata fromcoauth. codminuses the admin API withurn:coauth:adminorurn:arkret:admin:*.- A delegated/public DID resolver remains the identity registry / resolver source.
The Station may dispatch these account and identity operations to coauth:
/.well-known/openid-configuration/_arkret/gate/account/authentication-handoffs/_arkret/gate/account/session-grants/_arkret/find/directory/resolve-handle
The Station itself publishes /_arkret/describe; coauth does not expose
an independent role-local Describe. Its /_coauth/account/integration/describe
manifest is deployment-private administration metadata, not an Arkret
ServiceDescribe or public service-kind registration.
coauth hosts no DID documents (/.well-known/did.json, /did.json, and
/users/{id}/did.json were removed): DID hosting is the Station's
job — coland's embedded webvh provider serves
did:webvh documents under its own authority, and coauth only mints/registers
against it. coauth-issued artefacts (session grants, handle claims) are
verified via the introspection endpoints and the OAuth JWKS.
- OpenID Connect provider with authorization code, refresh token, client credentials, and device code grants
- Station-backed identity and handle resolution, and short-lived session grants with exact AccountId-bound Station introspection
- Local account lifecycle, password auth, upstream OAuth federation, and recovery workflows
- Admin APIs for sessions, tokens, users, clients, templates, connectors, and policy data
- Email / SMS notification runtime, rate limiting, CAPTCHA hooks, telemetry, and policy enforcement
just init-dev
just devjust dev also runs init-dev automatically. Initialization creates a random
32-byte master key only when missing, validates and retains an existing key,
and refuses to overwrite malformed data. The checked-in config.dev.yaml
uses:
.local/secrets/coauth-keystore-master-key # separately stored master key
.local/keystore/coauth.v1 # encrypted runtime key bundle
.local/media/ # local file-backed media
Account, OAuth and registration rows remain in PostgreSQL, just as Coland's
relational state does; .local/ contains only Coauth's file-backed local
artifacts.
coauth config generate > config.yamlhttp:
public_base_url: https://auth.example.com/
database:
uri: postgresql://coauth:password@localhost/coauth
arkret:
stations:
- name: coland
endpoint: https://coland.example.com/
embedded_webvh_registration_bearer: ${COLAND_WEBVH_REGISTRATION_BEARER}
identity_registry:
resolver: https://resolver.example.com/
proof_required_for_pairwise: true
admin_audience: ak:did_core:web:auth.example.com
secrets:
backend: encrypted_file
path: /var/lib/coauth/keystore.v1
master_key_file: /run/secrets/coauth_runtime_keys_master_key
passwords:
enabled: trueCoauth resolves and persists its service DID through the one configured
registration-capable entry. A standalone Provider uses the product-neutral
identity_services[] shape (name, endpoint, registration_bearer). If
more than one entry can register identities, set arkret.identity_provider to
the selected entry name.
coauth server --first-provisioning -c config.yamlRun the command with --first-provisioning exactly once when the configured
KeyStore is empty. Later server and worker starts omit the flag and load the
same durable key bundle. This runs migrations, syncs config-backed state,
starts the HTTP service, and launches the background worker unless disabled
with flags.
coauth is a Rust workspace. The frontend is a Dioxus app.
git clone https://github.com/arkret-org/coauth.git
cd coauth
# Backend binary only. The default configuration uses the Cedar policy engine.
cargo build --release -p coauth --features cedar
# Full production build with web assets (requires `just` and `dx`)
just build-all| Endpoint | Purpose |
|---|---|
/.well-known/openid-configuration |
OIDC discovery |
/_arkret/gate/account/authentication-handoffs |
Station Account Authority authentication handoff |
/_coauth/account/integration/describe |
Deployment-private integration metadata, not a public Arkret role |
/_arkret/find/directory/resolve-handle |
Handle -> DID resolution |
/_arkret/gate/account/session-grants/introspect |
Station session grant validation |
/_coauth/admin/* |
Admin API for codmin and service automation |
/_coauth/admin/openapi.yaml |
Coauth admin API OpenAPI document |
/.well-known/arkret/openapi.yaml |
Admin API discovery document for codmin |
- English configuration reference: docs/en/reference/configuration.md
- English scope reference: docs/en/reference/scopes.md
- Chinese configuration reference: docs/zh/reference/configuration.md
- Chinese scope reference: docs/zh/reference/scopes.md
Before exposing coauth to the public internet, walk every item below.
This is an operator checklist, not a runtime health endpoint. Use /healthz,
/readyz, and /metrics for automated monitoring, and see the
deployment hardening guide for
rollout details.
-
COAUTH_DEVELOPMENT_MODE=false(or unset in production builds) - TLS enabled at the reverse proxy (
COAUTH_TLS_CERT_PATH/COAUTH_TLS_KEY_PATHwhen terminated in-process) - CSP header configured at the reverse proxy
- CORS limited to the allowed origins for codmin / public clients
- Secrets in a secret manager (session-grant signing seed, OAuth client secrets, upstream provider creds)
- Log redaction enabled (default outside dev mode)
- Admin auth in production mode (admin capabilities + scopes, no dev-login)
- Rate limit enabled
- Provider credential rotation scheduled for upstream OAuth providers
coauth is distributed under AGPL-3.0-only. See LICENSE.