Skip to content

ADR-0007: Identity through the git provider, sessions and RBAC ​

Status: accepted (2026-10-12)

Decision ​

  • Users sign in with the git provider. For GitHub this is the user authorization flow of the configured GitHub App (/login/oauth/authorize with state and PKCE S256; token exchange at /login/oauth/access_token). There are no local passwords, TOTP or separate identity service. Generic OIDC (with Dex as optional broker) is specified in ADR-0013.
  • Identities live in the system-only users table, unique per provider, host and external id. Sessions live in the system-only auth_sessions table: only SHA-256 hashes of the session and CSRF tokens are stored; the GitHub user token is stored encrypted and the session never outlives it (8 h). Refresh tokens are not stored.
  • The session cookie is opaque, HttpOnly, Secure in production, SameSite=Lax, rotated at login. State-changing requests require the CSRF token header and, when present, an Origin equal to PUBLIC_URL.
  • Amendment: bearer tokens are accepted on /mcp only. Routes marked auth: 'bearer' authenticate with a personal MCP access token in the Authorization header, ignore cookies, need no CSRF token and still require an Origin equal to PUBLIC_URL when one is sent. Cookie routes never accept a bearer principal. Token format, grant derivation and freshness are specified in ADR-0018.
  • Every route declares a Permission in its route config; the app refuses to start otherwise. isAllowed(permission, grants) in @quavon/shared-types is the single permission matrix.
  • Grants are derived from GitHub and cached in tenant-scoped tenant_memberships / repo_memberships: org owners and members of the tenant's configured admin team are tenant admins; repo admin/maintain → maintainer, write → reviewer, read → reader. Repository roles only count for members of the installation's organisation, so read access to a public repository grants nothing.
  • Instance administration (GitHub Apps, OAuth settings, instance settings, instance audit) requires instance_admin. The first GitHub login that carries a valid setup session claims it; afterwards it is granted by an instance admin or the CLI.
  • Break-glass: a CLI command creates a single-use, short-lived link (setup_tokens.purpose = 'break_glass'). The resulting session has no user, is limited to instance administration and expires after one hour.
  • Every mutation writes an audit_log entry. Instance-level actions use tenant_id = null, which forms its own hash chain.
  • Secrets entered in the UI (GitHub App credentials, LLM keys) are encrypted with @quavon/crypto bound to <table>:<id>, returned only masked, and never logged.

Consequences &ZeroWidthSpace;

  • Role changes on GitHub reach Quavon within the cache TTL; mutations re-check grants that are older than a short threshold.

The open core is released under the Apache License 2.0.