Skip to content

tngan/samlify-starter

Repository files navigation

samlify-starter

A runnable tutorial for samlify — wire it up as a SAML 2.0 Service Provider against the IdPs most often asked about in samlify's issue tracker, with a parallel OIDC stack for comparison.

The repo is a single Node app that registers three SP tenants (finance, marketing, admin) and renders each tenant's session status as an iframe on a dashboard. Logging into one tenant fans out via real IdP-side SSO; one click triggers Single Logout across all three. The whoami iframes don't care which protocol fed the session.

UI is Tokyo Night (dark by default).

About the build. Fully vibed with Claude — designed, built, and iterated end-to-end. It keeps evolving, so treat it as a starter + demo showcase: read docs/99-troubleshooting.md when something doesn't work, and do your own research before adapting any of it to production. PRs welcome for more IdP integrations, enhancements, and bug fixes.

Quickstart

Prereqs: Node ≥ 20, pnpm.

./scripts/gen-keys.sh    # SP signing certs + IdP keypair (one-off)
pnpm install
pnpm dev                 # picks a free port from 5173 upward

Open the printed URL. The default IdP is samlify (in-process IdP) — both sides of the SAML round-trip live in this same process. Pick a tenant, click Login, sign in as alice / alice, watch all three tenant iframes flip to logged in. Single Logout (all) drops every session at once.

For a real local IdP via Docker:

pnpm keycloak:up         # seeds realm with SP certs, then `docker compose up -d`

Then pick Keycloak (local Docker) in the dashboard.

Architecture

┌──────────────────────────────────────────────────────────┐
│  Dashboard (/)                                           │
│    └─ iframe per tenant → /tenants/<t>/whoami            │
└──────────────────────────────────────────────────────────┘
                           │
                           ▼
┌──────────────────────────────────────────────────────────┐
│  samlify-starter (Remix + Hono on Node)                  │
│   SAML:    /sso/:tenant/:idp   /acs/:tenant              │
│            /metadata/:tenant   /slo/:tenant              │
│   OIDC:    /oidc/login/:tenant /oidc/callback/:tenant    │
│   In-process samlify IdP at /idp/*                       │
└──────────────────────────────────────────────────────────┘
                           │
              ┌────────────┴────────────┐
              ▼                         ▼
     External SAML IdP            External OIDC OP
     (Keycloak, Okta, …)          (node-oidc-provider sidecar, …)

The SAML protocol logic in server/saml/handlers.ts takes a Web Request and returns a Web Response — no framework lock-in. Remix mounts those handlers as resource routes for dev; server.mjs mounts the same handlers under Hono for production.

IdPs

IdP Setup Notes
samlify (in-process) none Default. alice / bob seeded; password = username for ad-hoc users.
node-oidc-provider (sidecar) pnpm oidc:up OIDC code flow on :5273.
Keycloak pnpm keycloak:up Local Docker; realm pre-seeded with SP signing certs.
Okta · Entra ID · ADFS · AWS IAM Identity Center · Auth0 · Google · OpenVPN · OneLogin · Ping · Authentik env-gated Set <IDP>_METADATA_URL (and E2E_<IDP>_USERNAME/PASSWORD for e2e). See docs/<idp>.md.

Per-IdP setup walkthroughs and known pitfalls live in /docs (also viewable at /docs/<slug> when the dev server is running).

End-to-end tests

pnpm test:e2e            # auto-discovers a port, spawns its own dev server
pnpm test:e2e:ui         # UI mode

The samlify, oidc-provider, and keycloak specs run unattended out of the box. Cloud-IdP specs are env-gated and self-skip without creds. To run against an already-running dev server: HUB_BASE_URL=http://localhost:5178 pnpm test:e2e.

Online tools

A /tools page in the dashboard ships a SAML message decoder, base64, raw-deflate, and XML formatter — all client-side. Useful for debugging when something on a real IdP isn't going through.

Configuration

  • SP crypto knobs — env-driven via SP_* (SP_AUTHN_REQUESTS_SIGNED, SP_SIGNATURE_ALGORITHM, SP_IS_ASSERTION_ENCRYPTED, etc.). Full table in docs/13-crypto-config.md.
  • Per-request — query params on /sso/:tenant/:idp: ?forceAuthn=true, ?username=<hint> (in-process IdP), ?chain=1 (chain login).
  • Per-IdP — the gear icon on each picker card opens a sidebar to override display name, metadata URL/XML, and (for the in-process IdP) NameID format + signature algorithm. Persisted in localStorage. See docs/16-config-sidebar.md.

Scripts

Script What it does
pnpm dev Remix vite dev (auto port discovery)
pnpm typecheck tsc --noEmit
pnpm build / pnpm start Production build + Hono server
pnpm gen-keys Generate SP signing certs + IdP keypair
pnpm keycloak:up / :down / :reseed Local Keycloak via Docker
pnpm oidc:up / :down OIDC OP sidecar (:5273)
pnpm test:e2e Playwright suite

Production checklist

Before adapting any of this for real users:

  • Replace the noop schema validator (server/saml/validator.ts) with @authenio/samlify-xsd-schema-validator or @authenio/samlify-node-xmllint.
  • Move sessions out of cookies into a server-side store.
  • Rotate SESSION_SECRET and all per-tenant signing/encryption keys; never commit them.
  • Set SP_AUTHN_REQUESTS_SIGNED=true, SP_WANT_ASSERTIONS_SIGNED=true, and SP_WANT_MESSAGE_SIGNED=true once your IdP supports it.
  • Generate separate encryption keypairs (GEN_ENC_KEYS=1 ./scripts/gen-keys.sh) and enable SP_IS_ASSERTION_ENCRYPTED=true if your threat model requires confidential assertions.
  • Add CSRF protection on /acs and /slo.
  • Pin samlify and validator versions; review samlify's security advisories.

License

MIT

About

Example repo

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors