Threadline ↔ Sigra integration

Copy Markdown View Source

Use Threadline.Integrations.Sigra when your Phoenix host already uses Sigra for request authentication and impersonation.

Install

Add Sigra to your host application's mix.exs as an optional dependency:

{:sigra, "~> 0.2", optional: true}

This dependency is for hosts; never for the library.

Plug callback wire-up

Wire Threadline.Plug directly with both callbacks in the router pipeline after your host has established request auth and any proxy-aware IP rewriting:

pipeline :api do
  plug :accepts, ["json"]
  plug Threadline.Plug,
    actor_fn: &Threadline.Integrations.Sigra.actor_ref_from_conn/1,
    context_overrides_fn: &Threadline.Integrations.Sigra.audit_context_overrides_from_conn/1
end

actor_fn decides who acted. context_overrides_fn can add only additive request metadata when the baseline conn extraction has no value.

Threadline.Plug always derives request_id from x-request-id first and correlation_id from x-correlation-id first. The Sigra callback is therefore supplemental: it fills missing values and never replaces an explicit header or already-derived actor identity. If the callback returns unknown keys or any non-map value, Threadline.Plug raises ArgumentError immediately.

Hosts still own transport normalization. If your deployment needs proxy-aware IP handling, rewrite conn.remote_ip upstream before Threadline.Plug runs.

Behaviors locked by SPEC

  1. Impersonation maps to :admin. When current_scope.impersonating_from is non-nil, actor_ref_from_conn/1 returns an admin actor and keeps the impersonated user encoded in correlation metadata.
  2. API token maps to :service_account. When current_scope.auth_method is :api_token or :jwt, actor_ref_from_conn/1 returns a service account actor using current_scope.id.
  3. Active organization adds a suffix. When Sigra exposes an active organization, the adapter appends :org:<id> to the derived correlation id.
  4. Anonymous / Sigra-absent returns nil. If the request has no supported Sigra actor shape, actor_ref_from_conn/1 returns raw nil.
  5. x-correlation-id header always wins. When the header is present, audit_context_overrides_from_conn/1 returns %{} so Threadline.Plug preserves the request value instead of replacing it.
  6. x-request-id and any existing actor identity also stay authoritative. context_overrides_fn is additive request metadata only; it is not a second actor path.
  7. Plug-only adapter; no telemetry subscription in v1.

correlation_id formats

  • Impersonation: sigra-imp:<session_id>:user:<imp_user_id>
  • Plain session: sigra-session:<session_id>
  • API token: sigra-token:<token_id>
  • Anonymous / Sigra absent: no override / %{}

Soft-dep contract

Code.ensure_loaded?(Sigra.Session) is the single soft-dependency gate.

When that check is false:

  • actor_ref_from_conn/1 returns nil
  • audit_context_overrides_from_conn/1 returns %{}