Building a member area on Core dna: who a member is in the data, the sign-in flows and their templates, single sign-on and passkeys, the my-account routing convention, members-only content, sessions and the page cache, and the security checks to run before launch.
L2
Unit 03 · Authenticators, SSO and linked accounts
Passkeys
Authenticators, SSO and linked accountsPage 20 of 36Updated
Members can sign in with a passkey instead of a password: a credential kept by their device or password manager. The settings, the script that runs the browser side, enrolling at registration or from the account, signing in, the management screen, and the browser and domain constraints to plan for.
Who this is for. The theme developer adding passkeys to a member site. Afterwards you can switch them on, add the markup to the sign-in, registration and account pages, and tell the client what members need.
The settings
In the OAuth module's settings, under Passkeys:
Setting
Default
Effect
Enable
Off
Passkeys on for the site
Forbid Backend Login
Off
On, passkeys cannot be used to sign in to the admin
Relying party ID
Empty: the hostname of each request
The domain passkeys belong to. Set a parent domain, such as example.com, only to share passkeys between its subdomains; it must be one of the site's hostnames or a parent of one. Changing it stops existing passkeys working
Relying party name
Empty: the site's name
The name the browser or password manager shows when a passkey is created
Require user verification
On
The device must verify the person (fingerprint, face, PIN or unlock) whenever a passkey is created or used
With passkeys on, the account templates receive passkeyEnabled, and the site answers /.well-known/passkey-endpoints, which tells devices where members manage their passkeys.
The script
The browser's side is done by a script the platform serves, /assets/passkeys.js. Include it on each page that uses passkeys, with the page's script nonce, and it wires up elements by their CSS classes and data- attributes; it also exposes window.CorednaPasskeys for code of your own. On pages for signed-in members it needs the CSRF token, which it finds in a data-csrf-token attribute on an enclosing element, among other places.
Enrolling a passkey
A passkey is added in one of two places, and both tie it to an account the person has proved is theirs:
From the account, signed in, on /my-account/passkeys (below).
At registration, instead of a password: the registration form posts passkey=1, the account is created, and the member is sent to the platform's /oauth/passkey/add page to create the passkey, within a short window and in the same browser. They are signed in once it is created. Show the option only when passkeyEnabled is true (The form).
A member whose account is linked to Core dna manages passkeys on their Core dna account, not on the site.
Signing in with a passkey
On the sign-in page, two pieces of markup do it: the username field offers the member's passkeys as they type, where the browser supports it, and a button signs in with a passkey on demand. The button stays hidden until the script finds the browser can use passkeys.
The username field must carry autocomplete="username webauthn" for the passkey suggestions to appear; a shared input partial that sets autocomplete="off" stops them. On success the script follows the platform's redirect, so the member lands where any sign-in lands. Errors appear in the element named by data-error-target, in plain words such as "Passkey request was cancelled or timed out. Please try again."
The passkeys screen
/my-account/passkeys, route passkeys in the MyAccount module, lists the member's passkeys and lets them add, rename and remove them. It renders users/passkeys/index.html. The framework ships one in Smarty that works as it is; override it to restyle, and on a Twig site write your own. It receives:
Variable
Holds
passkeys
The member's passkeys, each with getName(), getAuthenticatorName() (the password manager or device that made it, such as "iCloud Keychain", or nothing when unknown), getCreated(), getLastUsed() and isBackedUp()
passkeyEnabled
Whether passkeys are on for the site
passkeyAllowed
Whether this member may use them; false for accounts linked to Core dna
hasEmail
Whether the member has an email address, for recovering access if every passkey is lost
The buttons are markup for the script: an "Add a passkey" button with the class coredna-passkey-register and the options and add routes in data- attributes, and rename and remove buttons with the class coredna-passkey-action. Copy the framework's file as the starting point rather than writing the attributes from memory. Removing the member's last passkey takes passkey sign-in off their account, and is refused like any other last way in.
Constraints to plan for
Passkeys belong to a domain. A passkey created on a development or staging hostname does not work on the production domain, and members cannot carry passkeys between unrelated domains. Test enrolment and sign-in on the production hostname before launch, and do not change the relying party ID once members have passkeys.
Browser and device support. Current browsers on current operating systems support passkeys; the suggestions in the username field need a recent browser, and the script falls back to the button where they are missing. Keep another way in, a password or a provider, for members on older devices.
Recovery. A member who loses every device holding their passkey needs another way in. With an email address on the account, the forgotten-password flow is that way, so warn members without one, as the framework's screen does.
Administrators can see and remove a user's passkeys on the user's record in the admin, but cannot create one for them: creating a passkey needs the member's own device.