# Authentication

From [Descope Fundamentals](https://learn.descope.io/c/foundations) — Learn the platform by configuring your own project — every module ends in work the app checks for real.

Take this course interactively at https://learn.descope.io/c/foundations/b2c-authentication

---

![Magic Link, Enchanted Link, and Embedded Link. 2 minutes.](video:b2c-authentication-link-based-authentication)

These three methods all sign a user in through a link rather than a typed code, but they behave differently. The question that separates them is where the login session ends up, and who generates the link.

A magic link is a single-use link Descope sends by email or SMS. Clicking it opens a new browser tab and the session lands on that tab — the session follows the click. That makes magic links ideal when users sign in on a single device: start on the laptop, click the link in the laptop email client, end up logged in on the laptop.

An enchanted link is Descope's cross-device version, delivered by email only. The user begins login on one device — the originating device — and can click the link on another, say their phone. The session is validated back on the originating device, which quietly polls Descope until the link is clicked. For safety the user must pick the correct link out of several, or match a number shown on screen.

> [!WARNING]
> Number-matching is not designed to defeat a compromised inbox. Its job is to make the user pause and think before approving an unexpected login. Because the session stays on the originating device rather than following the link, enchanted links are more phishing-susceptible than magic links — worth calling out to stakeholders.

An embedded link is a magic-link token you generate on your own server using a management key, via the generate-embedded-link endpoint. Descope returns a token you drop into an email or message you send yourself, later verified with the standard Magic Link verify-token step. Reach for it when your application already sends its own transactional email and you want a ready-to-use, pre-authenticated link inside it.

## Key terms

- Magic Link — a single-use link (email or SMS); the session lands on the tab where the link is clicked.
- Enchanted Link — a cross-device, email-only link where the session stays on the originating device.
- Originating device — where an enchanted-link login was started and where the session completes.
- Embedded Link — a magic-link token generated server-side to place in your own messages.
- Management key — a privileged backend credential for server-side administrative calls.

![The Magic Link settings page under Authentication Methods. Expiration time and Number of retries are the two values worth setting deliberately — three minutes is short enough to limit a link that leaks and long enough to reach an inbox. Redirect URL above them is where the click lands, and the sibling methods in the left rail are Enchanted Link and Embedded Link.](b2c-authentication-link-based-authentication)

## Summary

- That with a magic link the session follows the click, and with an enchanted link it stays put
- Why the cross-device case (a smart TV, a kiosk) is exactly what enchanted links are for
- Why enchanted links carry more phishing risk, and what number-matching actually defends against
- When generating the token yourself with an embedded link is the right call

---

![OTP Authentication. 61 seconds.](video:b2c-authentication-otp-authentication)

A one-time password (OTP) is a short code Descope generates and sends to a user so they can prove they control a particular inbox or phone number. Think of it like a coat-check ticket: issued for a single use, and worthless once it has done its job.

The appeal is that it verifies a possession factor — proof of something the user has, rather than something they must remember. There is no password to forget, reset, or leak, and users already know the "enter the code we sent you" pattern. Delivery runs through a connector: a configured integration with a messaging provider such as SendGrid or Twilio.

> [!WARNING]
> Sending a new code invalidates the previous one. When a user requests a second OTP because the first "did not arrive", only the latest code will verify — a frequent source of confused support tickets.

Channel choice matters. SMS is the weakest option because of SIM-swap risk: an attacker who takes over the phone number intercepts the code. Prefer email, or use OTP as one factor within MFA rather than as the whole login.

## Key terms

- One-Time Password (OTP) — a single-use code sent to verify a user controls a given email or phone.
- Possession factor — proof of something the user has, as opposed to something they know.
- Connector — a configured integration with a messaging provider that delivers the code.

![The One-time Password settings. Expiry, how many retries a user gets and the window those retries are counted in sit under General; below them each delivery channel -- text message, voice call, email -- picks its own connector and message template, which is where the code physically comes from.](b2c-authentication-otp-authentication)

## Summary

- That OTP verifies a possession factor, with no password to remember or leak
- That issuing a new code invalidates the previous one
- Why SMS is the weakest channel, and what to prefer instead

---

![Passkeys and WebAuthn. 2 minutes.](video:b2c-authentication-passkeys-and-webauthn)

A passkey is a passwordless, phishing-resistant credential built on two open standards: WebAuthn, the browser API, and FIDO2, the broader specification behind it. Underneath is a key pair. The private key lives on the user's device or security key and is unlocked with a biometric or a device PIN; your application only ever stores the matching public key.

The passkey is like a physical key that never leaves the user's keyring, while your server holds only a keyhole shaped to fit it. Because the secret never travels, there is nothing for a phishing site to capture. At sign-in the browser runs the WebAuthn ceremony — prompting for the biometric or PIN — and returns a signed response to Descope.

> [!WARNING]
> Descope passkeys are domain-specific: one created on a given domain works only on that domain. Check the user.webAuthn key in a flow condition to see whether a valid passkey already exists for the current domain.

Not every device or browser supports WebAuthn, so a passkey-only login can lock some users out. Check device.webAuthnSupport in a flow condition before offering a passkey, and route unsupported devices to OTP, Magic Link, or password. Always provide a backup path.

It also helps to know where a passkey can live. A platform passkey is stored on the device or profile itself — Face ID, Windows Hello. An external passkey lives on a separate security key or another phone, which a user connects across devices by scanning a QR code.

## Key terms

- Passkey — a phishing-resistant credential; the private key stays on the device, the server stores only the public key.
- WebAuthn — the browser API that runs the passkey sign-in and registration ceremony.
- FIDO2 — the open standard behind passkeys, combining WebAuthn and the client-to-authenticator protocol.
- Platform vs. external passkey — stored on the local device or profile, versus on a separate security key or phone.

![Passkey settings, and the field that makes passkeys domain-specific: Top Level Domain. A passkey works on that domain and its subdomains and nowhere else, which is why the page refuses to let one be chosen until the project has an App URL. Display Name is what the authenticator shows the user at the prompt.](b2c-authentication-passkeys-and-webauthn)

## Summary

- That the server holds only the public key, so there is nothing to phish
- That passkeys are domain-specific, and which flow key reveals an existing one
- That device.webAuthnSupport must be checked and a fallback always offered
- Why passkeys are the recommended primary method in a passwordless strategy

---

![Password Authentication. 2 minutes.](video:b2c-authentication-password-authentication)

## What a policy controls

- Minimum length — default 8 — plus requirements for letters, lowercase, uppercase, numbers, and special characters
- Disallowed characters, and an option to block passwords matching the user's email
- Password expiration after a number of weeks, and prevent-reuse remembering the last N passwords
- Account lockout after too many failed attempts, or a temporary lock for a set number of minutes
- Password strength enforcement, from Very Weak up to Very Strong

When a user clicks "forgot password", Descope sends a reset email delivered as a Magic Link, whose connector and template you can customize. Administrators can also set or expire a password directly from the Users page — handy for issuing a temporary password and forcing a change on next login. In a flow, the user.passwordExpired dynamic key lets you branch on whether the password has expired.

Passwords are the weakest method, and the prime target for phishing and credential stuffing. They still fit when users expect them, when a customer or regulator requires them, or when you need a factor that works with no messaging channel at all. If you offer them, pair them with MFA rather than relying on passwords alone.

> [!NOTE]
> Migrating users? Descope imports existing password hashes (bcrypt, PBKDF2, and others) directly, so users sign in with their current password and no forced reset. When the old system cannot export hashes, set a freshlyMigrated flag on the imported user instead: a flow condition checks for it, routes them through a reset or re-verification on first login, then clears the flag.

## Key terms

- Password policy — the configurable rules (length, character mix, expiration, lockout, strength) a password must satisfy.
- Prevent password reuse — remembers the last N passwords and rejects them when a user sets a new one.
- Tenant — a single business customer in a B2B application; may carry its own, stricter policy.
- freshlyMigrated — a custom flag used in flows to route recently imported users through a first-login step.

![The Password Policy, which is the whole of what a password method is configured by: a minimum length, the character classes required, and then the optional rules that do the real work -- expiry, remembering the last N passwords to prevent reuse, locking an account after a number of failed attempts or locking it temporarily, and a minimum strength grade.](b2c-authentication-password-authentication)

## Summary

- That the default minimum length is 8, and tenant policies can only tighten rules
- That a multi-tenant user is held to the strictest combination of their tenants' policies
- That reset is delivered as a Magic Link, and admins can set or expire passwords from the Users page
- The two migration paths when password hashes cannot be exported

---

![Social Login and OAuth. 2 minutes.](video:b2c-authentication-social-login-and-oauth)

## The redirect sequence

- Start OAuth and send the user to the provider
- Receive the code back on your redirect URL
- Exchange that code for a token

> [!WARNING]
> A redirect URI mismatch between what the provider has and what Descope has is the single most common cause of a failing OAuth setup. They must match exactly — typically api.descope.com/v1/oauth/callback, or your custom-domain equivalent.

Account linking merges a social identity into an existing user — connecting someone's Google login to the account they already made with a password — typically via the Update User action and matching login IDs. A loginHint can pre-fill the provider's form with a known email.

A scope declares what your app may access from the provider. The openid scope is mandatory; email and profile are strongly recommended so you receive basic details. You can request custom scopes too — for Google Calendar, for instance, enable "Manage tokens from provider" so Descope securely stores the provider's access token and you can retrieve it later to act on the user's behalf.

## Key terms

- OAuth — the framework letting a user grant your app limited, delegated access through a provider.
- Scope — a declaration of what the app may access; openid is required.
- Redirect URI (OAuth callback) — the URL the provider returns the user to; must match on both sides.
- Account linking — merging a social identity into a user's existing account.
- Provider token — the provider's access token Descope can store to act on the user's behalf later.

![Social Login (OAuth / OIDC) under Authentication Methods. The providers Descope ships with are listed as cards, and each still needs its own client ID and secret from that provider before it will work. `+ Provider` is for an OIDC provider that is not on this list.](b2c-authentication-social-login-and-oauth)

## Summary

- That login completes when Descope exchanges the returned code for a session
- Which scopes are mandatory and which are merely recommended
- That redirect URI mismatches are the usual failure, and must match exactly
- When to use your own provider account, and how to reuse provider tokens

---

![TOTP and Recovery Codes. 2 minutes.](video:b2c-authentication-totp-and-recovery-codes)

A time-based one-time password (TOTP) is a rotating code produced by an authenticator app such as Google Authenticator, Microsoft Authenticator, or Authy. The app and Descope share a secret; combined with the current time, that secret generates a code that changes roughly every 30 seconds. Because the calculation happens on the device, TOTP works with no internet connection and no messaging channel at all. Configure it under Authentication Methods → Authenticator App.

At sign-in, the Sign In / TOTP action prompts for the current code. On success, verification returns the session and refresh tokens and logs the user in. In practice TOTP is most often used as a second factor within MFA rather than as a standalone login.

Enrollment hands the user a provisioning URL — a clickable link that opens the authenticator app with the secret ready to add — alongside the QR code and the raw seed for manual entry.

Recovery codes are single-use backup codes that let a user regain access when their primary second factor is unavailable: a lost phone, a wiped authenticator app, a misplaced security key. Without them, losing the device means losing the account, which is why they are issued at enrollment rather than on request.

## Key terms

- TOTP — a time-based one-time password generated by an authenticator app from a shared secret plus the current time.
- Seed (secret) — the shared value Descope generates for the authenticator app to produce codes from.
- Provisioning URL — a clickable link that opens the authenticator app with the secret ready to add.
- Recovery code — a single-use backup code for when the primary second factor is unavailable.

![The Recovery Codes settings page. Ten codes per generation is the default. The two lock settings below decide what happens when somebody guesses — a permanent lock after a number of attempts, or a temporary one that clears after a few minutes — and both are off until you tick them.](b2c-authentication-totp-and-recovery-codes)

## Summary

- How TOTP produces codes, and why it works offline
- That it is usually a second factor rather than a whole login
- What recovery codes protect against, and why they are issued at enrollment

---
