Product documentation
Thoryn — The Sovereign Identity Platform
A multi-tenant SaaS CIAM and identity-broker platform, available as a managed sovereign service or self-managed. Product white paper.
Thoryn — The Sovereign Identity Platform
Draft v1 — the flagship narrative for the fresh documentation program. Every claim below is grounded in the
sourcesabove and marked shipped vs. roadmap. Sections carry their own source anchors; deep detail links to the reference docs and ADRs rather than being restated here.
1. Executive summary
Thoryn is a multi-tenant SaaS platform for customer and workforce identity — an OAuth 2.0 / OpenID Connect authorization hub that brokers sign-in across a tenant's own users and any external identity provider, issues standards-compliant tokens, and governs access with role- and relationship-based authorization.
Two things make it distinctive:
- It is sovereign. Thoryn runs as an EU-operated managed service, and the same product can be self-managed by the customer for full data-residency and air-gap control. Delivery is dual and co-equal — you are never locked into someone else's cloud.
- The hub owns no user data. Thoryn is a broker: it issues tokens and moves claims, but user profiles, credentials, and organisation data live with the identity source. This is a deliberate architecture that keeps the trust surface small and the tenant boundary crisp.
It is a credible, sovereign alternative to Auth0, Okta Customer Identity, Microsoft Entra External ID, WorkOS, and Amazon Cognito — built on the same open standards, without the US-hyperscaler dependency.
2. Positioning
Who it is for. SaaS builders who need customer identity (CIAM) and B2B SSO; enterprises consolidating workforce access; and regulated or public-sector organisations for whom data sovereignty is a procurement requirement, not a nice-to-have.
The wedge — sovereign, and yours. The incumbent platforms are excellent and US-hosted. For a growing set of European buyers — public sector, finance, healthcare, defence-adjacent — that hosting is disqualifying (Schrems II, sector procurement rules, "buy European" mandates). Thoryn offers the same protocol surface and developer experience with EU-sovereign operation or self-hosting. You choose where your identity layer runs.
What it is not. Thoryn is a Hub identity product. It is not a verifiable-credentials or digital-wallet platform — that surface was deliberately separated out. The Hub does one thing: broker and govern identity, well.
Sources: CLAUDE.md, adrs/2026-07-01-hub-product-agnostic-platform.md.
3. Product overview — the identity-broker thesis
A traditional identity product stores your users and authenticates them. Thoryn brokers instead:
Relying party (your app)
│ OAuth 2.0 / OIDC
▼
Thoryn Authorization Hub ← tokens, claims, protocol only — no user data
│ PAR + OIDC (RFC 9126)
▼
Federation member ← owns the identity; one concern each
├── Thoryn Identity Service ← Thoryn-managed users (passwords, passkeys, MFA…)
└── Your enterprise IdP ← Entra ID / Okta / Google Workspace / any OIDC provider
The hub speaks OAuth/OIDC to your application and federation protocols to the identity
source. It mints the tokens, enforces the policy, and carries the claims — but it never
becomes the system of record for a person. If a feature would require the hub to store a
user table, that logic belongs in a federation member instead. This is enforced, not
aspirational: the hub codebase contains no User or Organisation entities.
The benefit is a small, auditable trust surface and a clean multi-tenant boundary — the two properties a security reviewer cares about most.
Sources: servers/authorization-hub/, servers/federation-members/identity-service/,
CLAUDE.md (identity-broker pattern).
4. Architecture
4.1 The four planes
- Broker plane (
authorization-hub) — the OAuth 2.0 / OIDC engine (Spring Authorization Server 7): authorize, PAR, token, revoke, introspect, userinfo, device-grant, DCR, logout, federation. - Identity plane (
federation-members/*) — the identity sources: Thoryn's own Identity Service, plus the tenant's own IdP attached as a federation member (Entra ID, Okta, Google Workspace, or any conformant OIDC provider). - Customer plane (
product-api+api-gateway) — the public, self-service management API and its ingress: tenant configuration, OAuth-client registration, federation management, RBAC/FGA, audit, compliance. - Operator plane (
admin/**) — Thoryn-internal cross-tenant operations, VPN-gated and separate. For self-managed deployments this is the customer's own operator surface.
4.2 Multi-tenancy and the per-tenant issuer model
Thoryn is multi-tenant to the core: each tenant is its own OIDC issuer
(https://{slug}.hub.<domain>, signed by a tenant-scoped key). A tnt claim minted at
the hub rides every token and is re-checked in every downstream service; cross-tenant
access returns 404, never 403 (no existence leak). The trusted-issuer allowlist is an
explicit SSRF boundary — an iss is honoured only if it is a known, non-suspended tenant,
and per-tenant key material is fetched from a fixed in-cluster service with only the Host
header varying, never an attacker-influenced URL.
This is what lets Thoryn host thousands of tenants on one deployment while giving each the cryptographic isolation of a dedicated issuer.
Sources: adrs/2026-06-08-multi-issuer-customer-plane-token-validation.md,
core/lib/common/.../security/TrustedTenantIssuers*, servers/authorization-hub/.../tenancy/.
5. Standards & protocol compliance
Thoryn is built on open standards — the same ones the incumbents implement, so your SDKs and integrations port directly.
| Capability | Standard |
|---|---|
| Authorization framework | OAuth 2.0 (RFC 6749), OAuth 2.1 posture |
| OIDC | OpenID Connect Core 1.0 |
| PKCE | RFC 7636 (enforced) |
| Pushed Authorization Requests | RFC 9126 (PAR-first authorize) |
| Device Authorization Grant | RFC 8628 |
| Token Revocation / Introspection | RFC 7009 / RFC 7662 |
| Bearer / DPoP / mTLS-bound tokens | RFC 6750 / 9449 / 8705 |
| Token Exchange | RFC 8693 |
| Rich Authorization Requests | RFC 9396 |
| JWT access-token profile | RFC 9068 |
| Dynamic Client Registration | RFC 7591 / 7592 |
| Step-up authentication | RFC 9470 |
| FAPI | FAPI 1.0 / 2.0 client profiles |
| Provisioning | SCIM 2.0 (inbound + outbound) |
A generated standards conformance matrix in the reference docs tracks the exact profile and status of each. Tokens are signed ES256 by a Vault/OpenBao Transit key — the signing key never leaves the secrets backend.
Sources: servers/authorization-hub/ endpoints, core/lib/fapi, core/starters/fapi,
adrs/2026-04-26-jwt-signing-strategy.md.
6. Authentication
Through the Thoryn Identity Service (or any federated source), tenants get a modern authentication stack:
- Passwordless-first: passkeys / WebAuthn (FIDO2), magic-link, and OATH TOTP/HOTP (including hardware tokens).
- Passwords with per-tenant strength policy, breached-password checks, and per-account lockout.
- Adaptive / risk-based auth: impossible-travel and geo-velocity detection, new-country notification, and risk signals that can drive step-up (RFC 9470) and LoA/ACR enforcement.
- Account lifecycle: email verification, password reset, self-service unlock, MFA recovery codes, active-session management and revocation.
Sources: servers/federation-members/identity-service/ (passkeys/, mfa/oath/,
magiclink/, risk/, lockout/, recovery/), core/lib/geoip, core/lib/sas/step-up.
7. Federation & connectors
A federation member is an identity source a tenant attaches. Provider behaviour is
dispatched through a FederationProvider interface — new providers are new
implementations, never if (provider == "X") branches — and per-tenant credentials are
Vault-envelope-encrypted, never held in JVM heap across requests.
- Self-service provider types: Microsoft Entra ID (
entra-id), Okta (okta), Google Workspace (google), and a generic OIDC provider (oidc) covering any conformant OpenID Connect IdP. These four are what a tenant admin can attach through the federation-member API and the console wizard; the same set is enforced inproduct-api, in the database CHECK constraints, and by the registry's implementations. - Domain-based routing: email-domain → tenant → connection, with just-in-time membership.
servers/federation-members/ additionally holds standalone connector applications
(JumpCloud, OneLogin, Apple, GitHub, LinkedIn, ADFS, PingFederate, a SAML 2.0 member, and
LDAP / ERP connectors). These present themselves to the hub as generic OIDC providers and
attach through an operator-managed path rather than the self-service API — they are
source-level connectors, not a shipped self-service capability. See
Federation runtime for the boundary.
Sources: servers/product-api/.../federation/FederationMemberService.kt,
servers/authorization-hub/.../federation/, servers/federation-members/*,
adrs/2026-05-20-multi-provider-federation-runtime.md.
8. Authorization
Thoryn ships two composable authorization models:
- RBAC — per-tenant roles and permissions, resolved into an effective permission set and (optionally) minted into the token as a coarse claim. The right tool for "what plan / role is this user."
- FGA (fine-grained / relationship-based authorization) — a Zanzibar-style engine:
relationship tuples (
object#relation@subject), an immutable authorization model, and a bounded-depth Check API that answers "can this subject do this to this object" at request time. It composes with RBAC, is never minted into a token (resolved live, fail-closed), and imports OpenFGA / Auth0-FGA models and tuples so you can migrate without rewriting your model.
Permissions ride as OAuth scopes under a tenant: namespace; operator scopes live under a
separate admin: namespace that structurally cannot reach the customer plane.
Sources: servers/product-api/.../rbac, servers/product-api/.../fga,
adrs/2026-07-01-rbac-authorization-model.md, adrs/2026-07-15-fine-grained-authorization-fga.md.
9. The customer plane — self-service by design
Everything a tenant configures, they configure themselves — this is what makes Thoryn a product, not a professional-services engagement.
- Console (web) and CLI (
thoryn) drive the same public product API through the API gateway. - Register and rotate OAuth clients (with a graceful 24-hour secret-overlap window), attach federation members, define RBAC roles / FGA models, set security and login policy, brand the hosted login page, manage users and invitations, and read a tamper-evident audit trail.
- The API is a first-class contract: RFC 9457 problem-details, camelCase, cursor
pagination, idempotency keys, a generated OpenAPI spec (drift-checked in CI), and a
clean
/api/v1/**surface with the tenant taken from the token, never the URL path.
Sources: servers/product-api/, servers/api-gateway/, docs/api/product-api.openapi.yaml,
adrs/2026-04-25-customer-plane-product-api.md, adrs/2026-07-01-api-platform-strategy.md.
10. CIAM & B2B
- User management — CRUD, metadata bags, bulk import (sync + async jobs), invitations, lifecycle (JML) workflows.
- SCIM 2.0 — inbound provisioning (Entra, Okta) and outbound push, with per-connection attribute mapping.
- Per-tenant experience — hosted-login branding, per-tenant and per-locale email templates, login-page i18n, login analytics.
- B2B organizations — organisations as tenant-scoped sub-entities, org-scoped roles,
per-organisation SSO connections, and email-domain routing with just-in-time membership
(on the org's SSO connection or a verified email domain), plus organisation invitations.
Managed through the product API at
/api/v1/organizations.
Sources: servers/federation-members/identity-service/ (users, scim, invitations,
emailtemplates, analytics), servers/product-api/.../organizations (org CRUD, connections,
domains, member roles, JIT membership), adrs/2026-07-15-b2b-organizations.md,
adrs/2026-07-16-b2b-organizations-org-sso-and-login-gate.md.
11. Extensibility
- Actions / Hooks — a programmable auth pipeline configured through the product API
(
/api/v1/hooks): inline stages that can modify or veto a token or a registration, and async event stages, delivered as signed webhooks — HMAC or Ed25519 detached-JWS — with per-stage fail-open/closed policy, delivery-health reporting, and graceful signing-key rotation. - Claims enrichment webhooks — per-client token-issuance webhooks that add claims,
SSRF-guarded and signed; delivered as the pipeline's inline
token.pre-issuancestage. - Federation-provider plugins — the
FederationProviderextension point. - OpenFGA import — bring an existing authorization model and tuple export.
Sources: servers/product-api/.../hooks, servers/authorization-hub/.../webhook/,
adrs/2026-07-15-actions-hooks-pipeline.md,
adrs/2026-07-20-asymmetric-hook-signing-ed25519.md, servers/product-api/.../fga.
12. Security & trust model
Security is the product. The highlights a reviewer will want:
- Signing in the secrets backend, not the JVM. All token and audit signing is ES256 via Vault/OpenBao Transit; keys never leave it. Per-tenant cryptographic identifiers are version-prefixed so a key can be rotated without breaking historical rows.
- Tenant isolation invariants.
tnt-claim enforcement everywhere; cross-tenant →404; the trusted-issuer allowlist as an explicit SSRF boundary. - Outbound-SSRF containment. Every outbound call to a tenant-influenced URL passes through a guard that rejects private / loopback / link-local / metadata addresses.
- Token security. Refresh-token replay/family-revocation detection, fingerprint binding, atomic single-use authorization codes.
- Error hygiene. One RFC 9457 error shape platform-wide;
detailstrings are sanitised by construction — no tenant ids or token contents leak. - Hardened by CI. A suite of build-time guards enforces these invariants (algorithm allow-lists, cookie attributes, no host-header-derived URLs, no unbounded blocking calls, no unsafe deserialization) so a regression can't merge.
- Privacy & compliance. GDPR data export (Art. 15) and erasure (Art. 17), per-tenant retention windows, a tamper-evident hash-chained audit trail, and NIS2 incident logging.
Sources: core/lib/signing, core/lib/common/.../security (OutboundUrlGuard,
TrustedTenantIssuers), servers/authorization-hub/.../{logout,authorization},
scripts/check-*.sh, adrs/2026-05-09-verifiable-audit-chain.md.
13. Delivery models
The same product, two ways — this is a first-class choice, not a footnote.
| Managed (sovereign SaaS) | Self-managed | |
|---|---|---|
| Runs where | EU-operated Thoryn cloud | Your Kubernetes |
| You operate | Nothing — Thoryn runs it | The full stack, via Helm |
| You configure | Tenants, clients, policy (self-service) | Same, plus infra |
| Best for | Fast start, sovereign hosting | Air-gap, full residency control, dedicated |
Both run the identical artefacts. Thoryn's operational discipline is the same artefact a self-managing customer runs: the entire deployed state is rebuildable from git with zero manual steps — Helm charts for infrastructure, Flyway migrations for schema, config as code. Secrets are OpenBao with auto-unseal; schema drift recovery is forward-patch-only (never destructive); readiness is tiered so a cold-start dependency blip can't crash-loop a healthy pod; and a Tier-3 synthetic monitor exercises real OAuth flows continuously.
That "rebuildable from git" property is simultaneously how Thoryn runs the managed service reliably and the thing you run yourself — which is why it earns first-class billing here.
Sources: deploy/helm/, CLAUDE.md (reproducible deployments),
adrs/2026-06-07-vault-to-openbao.md, servers/synthetic-monitor/.
14. Representative use cases
- B2B SaaS SSO — let your customers bring their own OIDC IdP (Entra ID, Okta, Google Workspace, or any conformant provider) and manage their users, with org-scoped roles.
- Customer identity (CIAM) — passwordless sign-in, social/enterprise federation, and fine-grained authorization for a consumer or prosumer app.
- Workforce access consolidation — one broker in front of many enterprise IdPs, with step-up and adaptive risk.
- Sovereign / regulated deployment — the self-managed model for an organisation that cannot use a US-hosted identity provider.
- Migration from Auth0 / Okta — standards-compatible tokens, SCIM, and OpenFGA/Auth0 model import to move without a rewrite.
15. Key architecture decisions
The reasoning behind the design lives in the Architecture Decision Records. The load-bearing
ones: the identity-broker / product-agnostic hub, the customer-plane boundary, multi-issuer
token validation, the JWT signing strategy, the multi-provider federation runtime, the
RBAC and FGA authorization models, and the OpenBao secrets cutover. The product/architecture
guide and the ADR index carry the detail.
16. Roadmap
Clearly separated from shipped capability. Per-tenant test / sandbox mode — a
Stripe-style livemode split where a tenant's test objects are segregated from its live
objects by the credential presented, with a distinct per-tenant test signing key and test
issuer. The machinery is built, but the capability is not yet generally available: the
resource-server opt-in (trustTestIssuers) stays fail-safe-off pending the identity
data-plane segregation, so test tokens are inert end-to-end today (see the security dossier's
flip-readiness assessment). Also in build: generated SDKs from the OpenAPI spec, and the
continued unification of the client-management surface. These are designed (ADRs merged) and
in build; they are not described above as if they exist today.
17. Where to go next
- Architecture guide —
product/architecture - Security & compliance dossier —
security/ - API reference (generated) —
reference/api - Get started —
get-started/