Software authenticator
Configure software WebAuthn credentials, handle registration save callbacks, and manage local or external signature counters.
Entitlement: softwareAuthenticator. EP: internal.software_authenticator. Websites use standard navigator.credentials.create() and get(), not a chrovia.softwareAuthenticator JS domain. Registration save replies additionally require messaging and a responsible Provision plugin.
Configure the authenticator
{
"internal": {
"software_authenticator": {
"config": {
"disguise_as": "windows_hello",
"display_name": "SDK Passkey Vault",
"counter_source": "local"
}
}
}
}| Field | Values/default |
|---|---|
config.disguise_as | windows_hello, icloud_keychain, gpm_phone; default gpm_phone |
config.display_name | Non-empty UI label; default Passkey Vault |
config.counter_source | external requests counters from your plugin for incrementing presets; otherwise local |
credentials | Array of serialized credential records, if importing previously saved credentials |
Choose how newly registered passkeys are presented to websites. These presets do not save passkeys to actual Windows Hello, iCloud, or a phone, and do not provide hardware-backed credentials. Changing the preset affects new registrations, not existing passkeys.
To test, fully restart with your configuration and save handler installed, open a site's account security settings, and choose to add a passkey. Select your configured vault name when offered and finish the site's confirmation. Sign out, choose passkey sign-in, and select the saved account if prompted. Keep an alternative sign-in method while testing.
Registration needs a save reply
Register this handler at every Provision Service Worker start. This minimal example approves local test registration; the kernel saves the record only after approval:
const messaging = globalThis.chrovia?.messaging;
if (messaging) {
messaging.on('chrovia.software_authenticator.credential.save', data => {
const channel = data?.callback_channel;
if (data?.action !== 'save_credential'
|| typeof channel !== 'string'
|| !channel.startsWith('chrovia.software_authenticator.credential.save.reply.')) {
return;
}
messaging.emit(channel, { success: true });
});
}The request carries a complete credential record, action: "save_credential", and callback_channel. Reply {success: true} to accept, or {success: false} to reject. Failure or no reply within 30 seconds rejects registration. Returning a value from the listener is not a reply.
For a managed vault, validate and durably save the record in your controlled storage before replying success. Do not log the payload: it contains sensitive sign-in data. Do not install two plugins that answer the same registration channel.
Use an HTTPS/localhost relying-party test site or Chrovia Studio's software-authenticator demo to register and sign in. Normal WebAuthn origin, RP, challenge, and server verification requirements still apply. A browser-side credential alone is not a server-registered account, and this capability does not promise unattended success for every site or headless flow.
Back up, restore, and remove passkeys
Treat each credential as an opaque record: preserve all its fields and values without decoding or reconstructing them. Use rp_id to identify the website, user_id to identify the account, credential_id to identify the passkey, and optional user_name / user_display_name for display. Keep identifiers exactly as received.
The save request contains these record fields at the top level, alongside action and callback_channel. Exclude those two message-routing fields when saving the record in your vault. Registering a new passkey for the same rp_id and user_id replaces the previous local passkey, so replace that account's vault entry rather than blindly appending another one. Wait for the site to confirm registration before relying on the new passkey.
To restore or remove local passkeys:
- Fully quit the instance and back up its current Extended Preferences file. Preserve a recent complete credential list from
internal.software_authenticator.credentials; it can contain updates made after registration. Reading throughchrovia.prefsadditionally requiresextendedPrefs. - Prepare the complete desired
credentialsarray from saved records. To remove a passkey, omit its record; to remove all, use an empty array. Preserve the rest of the document and authenticator configuration. - For unsigned preferences, replace
internal.software_authenticator.credentialsin the instance file while closed. For signed preferences, obtain a replacement signed file containing the desired list. - Restart the instance and test sign-in on the original website. Editing the list does not refresh an already-running instance.
Malformed or incomplete records can be skipped. Do not invent placeholders. Restoring a browser record does not register an account on the website, and removing it locally does not revoke the site's registration or delete copies in other vaults. Manage those separately in the site's account security settings. Keep backups and save payloads private; do not expose them to website scripts.
External counters
With counter_source: "external", the kernel can emit chrovia.software_authenticator.counter.claim with action: "claim_counter", rp_id, base64 credential_id, and callback_channel. Reply on that channel with {success: true, counter: "42"}, using a non-negative uint32 decimal string from an atomic allocation in your vault.
The allocation must be coordinated for the same credential across instances; do not reuse the constant example value. Failed, invalid, or missing replies fall back to local counter behavior after at most 30 seconds; they do not automatically reject sign-in.
External-counter requests apply to passkeys registered with windows_hello or icloud_keychain. The default gpm_phone preset reports zero and does not request external counters. Select an incrementing preset before registration when your integration needs counter allocation. Changing disguise_as later does not change existing passkeys.
Using signed preferences
With signedExtendedPrefs, passkey registration or sign-in can make the current EP file unusable on the next launch. Arrange to obtain an updated signed EP containing the latest credential list before restarting. A successful save reply does not update the signed file.
For unsigned local testing, use an issued License without signedExtendedPrefs.
TOTP secrets and saved passwords are different data and protocols. Do not store them as software WebAuthn credentials.