Lockspire + Sigra (same Phoenix host)

Copy Markdown

Lockspire is an embedded OAuth/OIDC authorization server for third-party clients of your API. Sigra is your end-user authentication stack (sessions, passwords, MFA, passkeys, “login with Google” via Assent, admin, audit).

This document is the Lockspire-side counterpart to Sigra’s recipe Companion OAuth provider (guides/recipes/companion-oauth-provider.md on hexdocs).

Boundaries (do not blur)

Own in Sigra / hostOwn in Lockspire
User table, sessions, MFA, passkeys, login UXClients, codes, tokens, consent protocol, JWKS, discovery
sub identity for your usersAuthorization decisions for external OAuth clients

Lockspire must not import Sigra at compile time. Integration is host-generated code: your AccountResolver reads the same session Sigra established, typically through conn.assigns.current_scope.user.

Install hint

mix lockspire.install --sigra-host

This adds Sigra-oriented comments (and @moduledoc) to the generated AccountResolver stub. You still implement real resolve_current_account/2 and claim building.

It does not create a second install topology. The canonical path is still mix lockspire.install; --sigra-host only adjusts guidance for the host-owned seam.

After wiring the generated files, use:

mix lockspire.verify

to confirm router wiring, seam presence, config, and migrations. Later, use mix lockspire.upgrade only for Lockspire-managed scaffolding; keep Sigra-facing resolver and UX code host-owned.

  1. Ship Sigra end-user auth first (register, login, orgs if needed).
  2. Add Lockspire; complete Phase 3 (OIDC + token lifecycle) before exposing third-party integrations broadly.
  3. Point login_path at your real Sigra login route; preserve return_to / interaction_id query params Lockspire needs, then resume the browser through the generated Lockspire interaction route after sign-in.

Host seam contract

For a Sigra-backed host, keep the seam narrow:

  • Read the signed-in user from conn.assigns.current_scope.user.
  • Build sub from a stable internal identifier, not email.
  • Keep the canonical example claim set narrow; richer profile or org claims remain host-owned decisions.
  • Preserve both return_to and interaction_id through your login bounce so Lockspire can resume the pending interaction safely.

The repo-owned proof for that shape lives in test/integration/phase6_onboarding_e2e_test.exs, which exercises unauthenticated /authorize -> host login -> interaction resume -> consent -> token exchange through generated-host code.

Planning

Cross-repo sequencing lives in Lockspire .planning/ECOSYSTEM-SIGRA.md.