To authenticate credentials that were migrated from U2F, you must use the FIDO AppID extension. This ensures the credentials are scoped to the original AppID rather than just the RP ID.
1. Server-side Configuration
Set the legacy_u2f_appid in your WebAuthn configuration. This tells the library to automatically request the appid extension when generating options for the authentication ceremony (options_for_get).
2. Frontend Implementation
When calling navigator.credentials.get(), you must check the client extension results. If the authenticator supports the AppID extension, the result will contain { "appid": true }. You must send this result to your backend along with the credential ID and response.
3. Verification
When PublicKeyCredentialWithAssertion#verify is called, the library will automatically detect if the appid extension was used. If appid is true, the library will correctly use the hash of the AppID (instead of the RP ID) to verify the assertion.
# 1. Configure the legacy AppID
WebAuthn.configure do |config|
config.legacy_u2f_appid = "https://login.example.com"
end
# 2. Generate options (appid extension is requested automatically)
options = WebAuthn::Credential.options_for_get
// 3. Frontend: Retrieve extension results
const credential = await navigator.credentials.get({ publicKey: credentialRequestOptions });
const clientDataJSON = JSON.parse(new TextDecoder().decode(credential.response.clientDataJSON));
const extensionResults = credential.getClientExtensionResults();
// Send 'extensionResults' (which contains { appid: true }) to your backend