Realms

A realm is one OIDC issuer — a self-contained login service with its own users, sign-in methods, assurance policy, and signing keys. This page covers creating realms and every setting on the realm settings page.

Creating a realm

In the admin console, open Realms and use the Create Realm card. There is a single field:

On submit, SemAuth automatically:

The realms list shows each realm's Name, Issuer ID (and custom domain if set), Status (Active / Disabled), and action links: Apps · Users · IDPs · Events · Settings · Discovery. The Discovery link opens the realm's /.well-known/openid-configuration.

Realm settings

Open Settings for a realm (/realms/{issuer_id}/settings). There are three cards.

Realm name

Change the display name. The value is trimmed and cannot be empty. Renaming never changes the issuer ID or any URL — it is purely cosmetic.

Authentication policy

The Minimum assurance dropdown sets the lowest authentication strength a sign-in must reach before this realm will issue tokens. Three options:

OptionMeaningSatisfied by
Any factor (AAL1)Any single factor is enough.Magic link, passkey, or federation.
Require MFA (AAL2)Multi-factor required.A passkey (today). One-time-code MFA arrives later.
Require phishing-resistant (AAL3)A phishing-resistant credential required.A passkey.

Guardrail. Because a passkey is currently the only factor stronger than AAL1, you can only select Require MFA or Require phishing-resistant when passkeys are enabled for the realm. Trying to set an unreachable floor is rejected ("This assurance level requires passkeys…") so you can't accidentally lock every user out at /authorize.

The full model — how each sign-in method maps to an assurance level, what the acr claim contains, and how step-up works — is on the Assurance levels page.

Enabling/disabling magic link & passkey. The two sign-in-method toggles (magic_link_enabled, passkey_enabled) are currently only changeable through the Admin API (PATCH /v1/realms/{issuer_id}), not from the settings page. New realms have both enabled.

Custom domain

Serve a realm at your own brand-aligned hostname (e.g. idp.acme.com) instead of the default {issuer_id}.semauth.app. Once active, the custom domain becomes the realm's iss, its JWKS URL, the link host in magic-link emails, the passkey binding (rp_id), and the federation callback target. The default host stays reachable as a fallback.

Set it before onboarding users. Changing the custom domain later invalidates every outstanding access token, refresh token, and passkey credential on the realm (the passkey binding is tied to the hostname). Configure it first, then onboard.

How to configure it

  1. At your DNS provider, add a CNAME record pointing your chosen hostname at the realm's canonical target shown in the UI: your-host CNAME {issuer_id}.semauth.app.
  2. Back in the settings card, enter the custom domain and click Verify CNAME & activate.

SemAuth resolves the CNAME chain (up to 5 hops) using public DNS resolvers only (Cloudflare 1.1.1.1 and Google 8.8.8.8) and activates the domain only if it points at the canonical target. TLS certificates are issued automatically on first request.

Rules and common errors:

To remove it, click Clear custom domain. The realm reverts to its canonical host; tokens issued for the custom hostname become invalid.

flowchart LR DNS["idp.acme.com<br/>CNAME"] --> Target["{issuer_id}.semauth.app"] Verify["Verify CNAME & activate"] -->|"resolves via 1.1.1.1 / 8.8.8.8"| Check{"Points at<br/>canonical target?"} Check -->|yes| Active["Custom domain active<br/>TLS auto-issued"] Check -->|no| Fail["Verification failed"]

Signing keys

Each realm has its own RSA 2048 key pair used to sign ID tokens and JWT access tokens with RS256. The active public key is published at the realm's /jwks.json, which is how resource servers and your apps verify tokens statelessly. Private keys are stored encrypted at rest. Keys are generated automatically at realm creation; rotation is event-driven (a new active key is added and the old one deactivated) rather than a manual button in the console today.

Disabling a realm

A disabled realm stops resolving — its hostname no longer serves OIDC endpoints. Re-enabling restores it. Realm enable/disable is available through the Admin API (PATCH /v1/realms/{issuer_id} with enabled).