How users sign in
SemAuth is passwordless. End users sign in to a realm with a magic link, a passkey, or a federated provider. This page covers the end-user experience of each and how you, the administrator, enable them.
The login page
When your app redirects a user to /authorize and they have no usable session, SemAuth shows the
realm's login page. It renders only the methods the realm has enabled:
- Federation buttons at the top — one "Sign in with {name}" per enabled external IDP.
- Passkey — a "Sign in with a passkey" button (shown only if the browser supports WebAuthn).
- Magic link — an email field and a "Send login link" button.
If the user already has a valid session that meets the realm's assurance floor,
the login page is skipped entirely and the authorization code is issued immediately. If a realm has no sign-in
method enabled at all, /authorize returns an error — always keep at least one enabled.
Magic links
Enabling it
Magic link is enabled by default on new realms (the magic_link_enabled setting; today toggled via the
Admin API). SemAuth sends the link by email — no setup required on your side.
The user experience
- The user types their email and clicks Send login link.
- They see a "Check your email" page. SemAuth emails a message titled "Your SemAuth login link" containing a single click-through link.
- Clicking the link verifies their email (creating the account on first use for normal realms), starts a session, and continues the original sign-in.
The link is single-use and expires after 15 minutes. A used or expired link shows a friendly "already verified" / "expired" page.
Same device vs. different device. If the user clicks the link in the same browser they started in, they're returned straight into your app's login flow. If they open it on a different device, they see an "Email verified — you can close this tab" page (cross-device continuation isn't carried over).
Magic-link requests are rate-limited (per email and per IP) to resist abuse; over-limit requests get a 429.
Passkeys (WebAuthn / FIDO2)
A passkey is a cryptographic credential stored on the user's device — unlocked by fingerprint, face, or PIN. It is phishing-resistant and earns AAL3.
Enabling it
Passkey is enabled by default on new realms (passkey_enabled). The passkey is bound to the realm's
hostname (rp_id) — its default issuer host, or the custom domain if one is set.
Custom domain first. Because passkeys are bound to the hostname, switching a realm's custom domain on or off invalidates all existing passkeys. Set the custom domain before users enroll.
Enrolling a passkey
After a magic-link sign-in, a user who has no passkey is offered a "Secure your account" screen
with an optional device name (e.g. "MacBook") and a Create Passkey button. They can
Skip for now — unless the realm requires AAL2+, in which case skipping is hidden because a passkey
is mandatory to reach the floor. Users can also enroll later from /account/passkeys.
Signing in with a passkey
On the login page the user clicks "Sign in with a passkey", the browser prompts for their biometric/PIN, and they're signed in. SemAuth uses discoverable credentials, so on supporting browsers the passkey is even offered directly from the email field via autofill — no need to type anything. A clone- detection counter protects against duplicated authenticators.
Managing passkeys
At /account/passkeys a user sees each passkey's name, when it was registered, and when it was last
used, with a Revoke button. Revoked passkeys stop working immediately.
Federated sign-in
If the realm has external IDPs configured, the user can click "Sign in with {provider}" and authenticate with their existing Google / LinkedIn / OIDC account. SemAuth verifies the provider's response, matches or creates the local user, and continues the flow. The full setup and account-matching rules are on the External identity providers page. Federated sign-ins currently count as AAL1.
Which method should I enable?
| Goal | Recommendation |
|---|---|
| Lowest-friction onboarding | Magic link + passkey (the default). Users start with a link, then enroll a passkey for speed. |
| Strong security baseline | Set the realm floor to "Require phishing-resistant" so every session ends up passkey-backed. |
| Reuse corporate identity | Add Google / generic OIDC federation so employees use their existing accounts. |