Passkeys
A passkey lets someone sign in with their fingerprint, face or device PIN instead of typing a password. It's kept on their device, in their password manager or on their phone, it works only on the site it was made for, and it can't be phished or reused elsewhere. Power Portals Pro adds passkeys to a portal's local accounts on both React and Blazor: users add them on their account page, then sign in with one in a single step.
Turning passkeys off
Passkeys are on wherever local accounts are (LocalAccountsEnabled, on by default): a passkey is a local credential, kept for a contact as a password is. For a portal that shouldn't offer them, set PasskeysEnabled on AuthClientOptions to false in Program.cs. Turned off, the server stops serving the passkey routes and refuses passkey sign-in, the account pages stop showing them, and passkeys already saved can no longer be used.
builder.Services.Configure<AuthClientOptions>(options => options.PasskeysEnabled = false);
Important
Passkeys are kept in the
ppp_passkeytable, which the Power Portals Pro managed solution provisions. Import the solution before the account pages offer passkeys, and make sure the portal's application user holds the shipped application-user role, which carries its privileges on the table.
In the account pages
The account pages the project templates generate show passkeys whenever they're on: a Sign in with a passkey button on the login page, beside the password form, and a Passkeys section on the profile page where the user adds, renames and removes theirs. Both read passkeysEnabled from GET /api/auth/options, or AuthClientOptions on a Blazor Server page, and show nothing while passkeys are off.
The components
Two components, on both stacks, do the work. PasskeySignInButton signs in with a passkey the person chooses, and renders nothing in a browser that can't use passkeys. PasskeyManager lists the signed-in user's passkeys and lets them add, rename and remove them. Show them only while passkeys are on.
React
import { LoginResult } from '@powerportalspro/core';
import { PasskeyManager, PasskeySignInButton } from '@powerportalspro/react-fluent';
// On the sign-in page, when GET /api/auth/options reports passkeysEnabled
<PasskeySignInButton onResult={(result) => result === LoginResult.Success && navigate(returnUrl)} />
// On the signed-in user's account page
<PasskeyManager />
Blazor
@* On the sign-in page, when passkeys are on *@
<PasskeySignInButton ReturnUrl="@ReturnUrl" OnResult="OnPasskeyResult" />
@* On the signed-in user's account page *@
<PasskeyManager />
Once signed in, the Blazor button loads the page afresh at ReturnUrl, so everything on it sees the user signed in. OnResult hands the page the outcomes it handles itself, such as a locked-out account. The browser part of the ceremony runs in the components' own scripts, so they work alike under Blazor Server, WebAssembly and Auto.
How a ceremony works
Each passkey operation is two requests, built on ASP.NET Core Identity's passkey support: the first returns the options the browser passes to navigator.credentials, and the second sends back what the browser answered. Identity keeps the challenge between them in a cookie.
- Signing in:
POST /api/auth/passkey/request-options, thenPOST /api/auth/passkey/login, which checks the signature against the stored public key and signs the user in. Both count towards the per-address limit on sign-in forms. - Managing:
GET /api/auth/manage/passkeyslists them;POST /api/auth/manage/passkeys/creation-optionsandPOST /api/auth/manage/passkeysadd one;/renameand/removedo what they say. On React,AuthClient.signInWithPasskeyAsyncandcreatePasskeyAsyncrun a whole ceremony in one call.
Security
- A passkey that checks the person's PIN or biometric is two factors in itself, so a passkey sign-in asks for no authenticator code. A locked-out or unconfirmed account is refused, as at password sign-in.
- A passkey works only on the domain it was made on. If the portal moves to another domain, or a staging slot has its own hostname, existing passkeys don't work there. Set
IdentityPasskeyOptions.ServerDomainto pin the domain passkeys are made for. ppp_passkeyis a protected table: no portal request reaches it, whatever a role or a security role grants. The sign-in and account code reads and writes it as the application. What it holds — a public key and the data the browser signed — isn't secret.- An administrator impersonating a user can't add or remove the user's passkeys, as they can't change the user's password.
- Internal users sign in through Microsoft Entra ID, which keeps their passkeys; they have none in the portal.
Note
Browsers allow passkeys only on secure origins:
https, orlocalhostwhile developing.
