This is the canonical Day-1 onboarding path for Relyra. Follow the sections in order:
- Install
- Scaffold
- Prove local login with TestSupport
- Choose one provider runbook
- Production follow-ons
If you need broader context, return to the README. Do not start with optional admin or operations surfaces before the local proof works.
If you want the narrative explanation of what these steps are buying you, read Jobs To Be Done And User Flows after you finish this guide once.
Patch releases on main are automated via release-please (no manual version
bumps in this guide).
1. Install
Add Relyra to your host application's dependencies:
def deps do
[
{:relyra, "~> 1.5"}
]
endFetch dependencies:
mix deps.get
Why this comes first:
- It confirms the host can resolve and compile the package.
- It keeps the first receipt local and deterministic.
- It avoids mixing provider admin work into the install step.
Receipt: mix deps.get completes and mix compile succeeds in the host app.
2. Scaffold
Run the blessed scaffold command from the host application:
mix relyra.install --module MyApp --repo MyApp.Repo
The installer sets up the minimal host-side surface without pretending to finish every app-specific decision for you. Review the generated instructions, wire the router seams it asks for, and keep the host application's naming consistent with your actual module and repo names.
At this stage you should have:
- The Relyra dependency installed.
- Generated starter files from
mix relyra.install. - The Phoenix router and ACS-related seams wired per the generated instructions.
Receipt: the installer runs cleanly, the generated files exist, and your host app still boots after you apply the scaffold instructions.
3. Prove local login with TestSupport
Before touching a real IdP, prove the local trust path with
use Relyra.TestSupport, endpoint: …. FakeIdP signing is internal to the macro
helpers — you focus on wiring a stub ACS route and asserting the login receipt.
Prerequisites:
- A host ExUnit test module with Phoenix test deps (
Phoenix.ConnTest, router). - A minimal test router and ACS controller (not production
saml_routes()).
Stub router and controller (adapt module names to your host app):
defmodule MyAppWeb.TestRouter do
use Phoenix.Router
post("/:connection_id/acs", MyAppWeb.TestAcsController, :acs)
end
defmodule MyAppWeb.TestAcsController do
use Phoenix.Controller, formats: [html: "Phoenix.HTML"]
def acs(conn, _params) do
conn
|> Plug.Conn.assign(:current_user, %{email: "alice@example.com"})
|> Phoenix.Controller.text("ok")
end
endIntegration test using the TestSupport macro:
defmodule MyAppWeb.SamlLoginTest do
use ExUnit.Case, async: false
use Relyra.TestSupport, endpoint: MyAppWeb.TestRouter
test "local SAML login round-trip" do
conn = Phoenix.ConnTest.build_conn() |> setup_saml_connection(connection_id: "demo")
response = build_saml_response() |> sign_saml_response()
conn = post_saml_response(conn, Base.decode64!(response, padding: false))
assert_saml_login(conn, %{email: "alice@example.com"})
end
endCopy-paste source of truth: test/test_support_demo_test.exs in the Relyra repo.
Maintainers: doc CI gate
The demo test path is also checked by `mix ci.docs` in the Relyra repository.Stub vs production ACS: The §3 stub assigns :current_user directly for a
fast receipt. The §2 install scaffold wires import Relyra.Phoenix.Router; saml_routes() to Relyra.Phoenix.Controllers.ACSController and
consume_response/3 — use that for real integration after this proof.
If this step fails, fix it here. Do not move to a hosted IdP until the local proof is stable.
Receipt: a host-side test passes with assert_saml_login/2 (or saml_login/1
returns {:ok, …}) after post_saml_response/2 dispatches to your stub ACS route.
4. Choose one provider runbook
Choose exactly one first-class batteries-included provider and finish that runbook before you return to production follow-ons:
- Okta runbook at
guides/recipes/okta.md - Microsoft Entra ID runbook at
guides/recipes/entra.md - Google Workspace runbook at
guides/recipes/google_workspace.md - ADFS runbook at
guides/recipes/adfs.md
Use one branch only for Day-1. The goal is to finish one real provider path, not to compare several admins in parallel.
Support taxonomy:
- Batteries included: Okta, Microsoft Entra ID, Google Workspace, and ADFS — each has a shipped preset module and repo-native runbook (Okta, Entra, Google, ADFS).
- Custom SAML: use the generic operator runbook at guides/recipes/generic_saml.md when you own the provider-specific mapping and verification work yourself.
- ADFS note: prefer guides/recipes/adfs.md when signed AuthnRequests or ADFS-specific encoding are part of the contract.
- Not yet shipped: any provider without a shipped preset module and verified repo-native runbook.
For custom SAML providers, adapt the same install -> scaffold -> local proof ->
real provider pattern, starting from guides/recipes/generic_saml.md, but do not
treat that path as first-class batteries included support.
Receipt: one provider runbook is completed and you have one real-provider login, metadata import, or equivalent provider-specific success proof from that runbook.
5. Production follow-ons
Once one provider path works, move to the operator-owned follow-ons that make the integration production-ready. After your first provider login, follow the Production Ecto path before scaling to multi-node production.
Recommended order:
- Confirm your metadata and certificate lifecycle plan.
- Wire audit and telemetry consumption in the host app.
- Decide whether you want the optional LiveAdmin surface.
- Configure scheduled refresh only after trust fingerprints and operator review are understood.
- Add diagnostic bundle handling to your support workflow.
Important posture:
- LiveAdmin is optional and comes late.
- Day-2 operations should not block the first successful login.
- The host application still owns its domain routing, session model, and application-specific authorization seams.
Useful follow-on references:
After your first successful login, bookmark the incident playbook for on-call Diagnose workflows.
- Production Ecto path — migrate from install ETS defaults to cluster-safe ConnectionResolver and RequestStore/ReplayStore Ecto adapters.
- Incident playbook — login trace & evidence surfaces — evidence surfaces,
mix relyra.trace, and scenario runbooks for Day-2 SAML incidents (login-trace LiveView at/relyra/admin/connections/:connection_id/trace). - guides/identity_mapping_and_provisioning.md for the host-owned anchor, lookup, and JIT decisions that come after a working provider path.
- Jobs To Be Done And User Flows
SECURITY.mdSECURITY_REVIEW.md
Receipt: you have one working provider path plus a written production follow-on plan for metadata, certificates, audit/telemetry, and any optional admin surface.
Appendix: Advanced manual response construction
Power users may call FakeIdP builders directly when debugging signing or metadata without ConnTest dispatch. This path skips router dispatch — prefer §3 for the recommended round-trip.
metadata = Relyra.TestSupport.fake_idp_metadata()
response =
[]
|> Relyra.TestSupport.build_saml_response()
|> Relyra.TestSupport.sign_saml_response()sign_saml_response/2 returns base64; decode before post_saml_response/2 in
macro tests. See §3. Prove local login with TestSupport
for the full integration path.