Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

IDENTITY FUNDAMENTALS · LAB

Sign in as Ava, then make her sign-in multi-factor

Watch your tenant check Ava's password, register an authenticator app and a passkey to her account, and read the evidence of each sign-in in amr and Audit.

ReadyUses your lab tenant

The lesson

Builds on: What is Identity?.

New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.

Your progress

Press Start before you begin. Only events your tenant records after that count, in the order below. Checking reads your tenant's Audit, so you need Audit read access in it.

  1. Sign in as Ava with her password

    Recorded as account.sign_in succeeded (signed_in) about [email protected].

  2. Try a wrong password

    Recorded as account.sign_in rejected (invalid_credentials).

  3. Register an authenticator to Ava's account

    Recorded as account.enroll succeeded (method_enrolled) about [email protected].

  4. Complete a second step as Ava

    Recorded as account.second_step succeeded (second_step_completed) about [email protected].

  5. Use one recovery code

    Recorded as account.second_step succeeded (recovery_code_used).

Setup

You need Ava's password from the first lab and an authenticator app on your phone. A passkey-capable browser or a security key is optional.

  1. On this lab page choose Lab Photos and press Start.

  2. Authentication > Authenticator app: set it to Optional with the issuer name Lab Photos. Save.

  3. Authentication > Passkey or security key: set it to Optional and keep the other defaults. Save.

  4. Confirm that the second step setting is the default: users who have registered a second step are asked for it.

  5. Set the issuer in your shell:

ISSUER=https://tenant-<id>.beyondthelogin.dev

Walkthrough

  1. In a private window open $ISSUER/login and sign in as Ava. You land on /account.

Why it matters: the email identified the account; the password was the evidence supporting her claim to use it.

  1. Sign out. Try Ava with a wrong password, then [email protected] with any password. Both attempts get the same message and the same 401 status. In Audit, both account.sign_in rejections have no actor.

Why it matters: typing an email address is only a claim. Nobody was authenticated, so the tenant records no actor and the page reveals nothing about which accounts exist.

  1. Sign in as Ava through $ISSUER/token-decoder with openid profile. The ID token has "amr": ["pwd"] and an auth_time.

  2. As Ava open $ISSUER/account/security and add an authenticator app. Scan the QR code, enter the current code, and store the recovery codes somewhere safe.

Why it matters: the authenticator works for Ava only because it was registered to her account while she was signed in. Holding some authenticator app is not enough; the association made through a trusted process is what counts.

  1. Sign out and sign in again at $ISSUER/login. After the password you land on /login/verify and enter the six-digit code.

  2. In the Token Decoder, tick the option that asks for a fresh sign-in (prompt=login) and sign in again with the password and code. The new ID token has "amr": ["pwd", "otp", "mfa"].

Why it matters: mfa appears because the second step is a different kind of factor, something you have rather than something you know. A second password on a second screen would not earn it.

  1. As Ava, open /account/security again and register a passkey. Sign out. Open DevTools > Network, then sign in with the passkey from /login. Find the options response with a random challenge, and the request your browser sends back with authenticatorData, clientDataJSON and a signature. Your fingerprint, face or PIN is nowhere in it.

Why it matters: the biometric or PIN unlocks the authenticator on your device, which then proves control to the tenant with a signature over the tenant's challenge. The fingerprint itself never reaches the website, and the signature is bound to the tenant's own origin.

  1. In the Token Decoder with a fresh sign-in requested, sign in with the passkey. amr shows swk for a synced passkey or hwk for a key that stays on one device, plus mfa when the device verified you.

  2. As Ava open $ISSUER/manage. You are sent back to /account.

Why it matters: Ava is authenticated, but she holds no management role. Deciding what she may do is authorization, the subject of the next lab.

Break it

  1. Sign in with the password, and at /login/verify enter a wrong code three times. Each is refused and Audit shows account.second_step rejected. Stop after three; repeated failures are limited per day.

  2. Now use one recovery code instead of the authenticator code. Audit shows account.second_step with reason recovery_code_used. At the next sign-in, try the same recovery code again: it is refused, because each code works once.

Why it matters: a recovery code is still evidence of control, but single use limits how long a copied code is worth anything.

Check your work

Press Check my progress. It looks for:

  • account.sign_in succeeded with reason signed_in for Ava, and rejected with reason invalid_credentials.

  • account.enroll succeeded with reason method_enrolled for Ava.

  • account.second_step succeeded with reason second_step_completed for Ava.

  • account.second_step succeeded with reason recovery_code_used.

Compare the three ID tokens you collected: ["pwd"], ["pwd", "otp", "mfa"] and the passkey's amr.

Cleanup

  1. Keep Ava's authenticator app, her passkey and the Optional settings. Later labs rely on Ava having a second step.

  2. Store Ava's remaining recovery codes with her password.

Back to all labs

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

The Lab