Setting up a method
Give signed-in users a Two-step sign-in section in their settings. Offer what getMethods allows.
Authenticator codes
Section titled “Authenticator codes”enrollTotp(userId, label)returnsqrCode(a PNG data URI for an<img>),secret(to type in by hand) and the method, stillPENDING.- The user scans it with Tenon Authenticator or any authenticator app, and types the first code.
activateFactor(userId, factorId, code): the method is active, and it replaces their previous one. A wrong code throwsInvalidCode: let them try again. After 15 minutes or 5 wrong codes, start again (enrollment_expired).
TotpEnrollment totp = tenonAuth.enrollTotp(user.id(), "Customer portal");// Page: <img src="${totp.qrCode()}">, totp.secret(), a field for the first code.tenonAuth.activateFactor(user.id(), totp.factor().id(), code);const totp = await tenonAuth.enrollTotp(user.id, 'Customer portal');// Page: <img src={totp.qrCode}>, totp.secret, a field for the first code.await tenonAuth.activateFactor(user.id, totp.factor.id, code);totp = tenon_auth.enroll_totp(user.id, "Customer portal")# Page: <img src="{{ totp.qr_code }}">, totp.secret, a field for the first code.tenon_auth.activate_factor(user.id, totp.factor.id, code)var totp = await tenonAuth.EnrollTotpAsync(user.Id, "Customer portal");// Page: <img src="@totp.QrCode">, totp.Secret, a field for the first code.await tenonAuth.ActivateFactorAsync(user.Id, totp.Factor.Id, code);Sign-in approval (Tenon Authenticator)
Section titled “Sign-in approval (Tenon Authenticator)”enrollPush(userId, label)returnsqrCode,enrollmentUri(a link that opens the app on the same phone) andactivationNumber.- The user scans the QR code with Tenon Authenticator, and types the activation number your page shows.
- Poll
listFactorsevery 3 seconds until:- the method is
ACTIVE: done, and it replaced their previous one; - it is gone: they typed a wrong number, so start again;
expiresAthas passed.
- the method is
Email codes
Section titled “Email codes”Only when getMethods().emailAllowed, and only for the listed domains when there are any.
enrollEmail(userId, email, label, language)sends a code to the address. Take the address from your own records, e.g. the company directory, rather than letting users type any.- The user types the code:
activateFactor.
Errors:
EmailRefusedwithemail_codes_not_allowedoremail_domain_not_allowed;TooManyRequests;EmailUnavailable: no email could be sent, so try later.
Then: recovery codes
Section titled “Then: recovery codes”Right after a method becomes active, call createRecoveryCodes(userId) and show the 10 codes once, with Download and Print. They replace any older codes. Show getRecoveryCodes(userId).remaining in the settings, and offer new codes when few are left.
Turning it off
Section titled “Turning it off”deleteFactor(userId, factorId) removes the method. The user’s remembered devices and recovery codes stop working with it. Whether a user may turn the second step off at all is your policy.