mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-12 16:10:30 +02:00
fix(core): Trust BE method on register and hint authenticator class
- Registration verify endpoint now returns the actual `method` classified from the WebAuthn response (`transports` / `credentialDeviceType`). The frontend uses this instead of the attachment hint it sent, so when the OS routes a "security key" request through iCloud Keychain (or any other platform authenticator), the UI reflects what was actually registered and the state survives a page refresh. - Add `hints: ['security-key' | 'client-device']` to registration options so Chrome skips its platform-passkey dialog and goes straight to the matching prompt. - Rename "Switch to this" → "Set up" for the inactive 2FA method card.
This commit is contained in:
parent
3df9905815
commit
824c1cc663
|
|
@ -323,6 +323,10 @@ export class MFAController {
|
|||
id: savedCredential.id,
|
||||
credentialId: savedCredential.credentialId,
|
||||
label: savedCredential.label,
|
||||
// The OS picker may route a cross-platform request through a platform
|
||||
// authenticator (e.g. iCloud Keychain), so the actual method is
|
||||
// derived from the response — not the client's attachment hint.
|
||||
method,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,13 @@ export class WebAuthnService {
|
|||
authenticatorSelection,
|
||||
});
|
||||
|
||||
// Hint the browser at the intended authenticator class. Chrome respects
|
||||
// this and skips its platform-passkey dialog when `security-key` is
|
||||
// hinted, going straight to the "insert your key" prompt. @simplewebauthn
|
||||
// doesn't type the field yet, so attach it post-generation.
|
||||
const hint = attachment === 'platform' ? 'client-device' : 'security-key';
|
||||
(options as typeof options & { hints: string[] }).hints = [hint];
|
||||
|
||||
await this.cacheService.set(
|
||||
`webauthn:challenge:reg:${userId}`,
|
||||
options.challenge,
|
||||
|
|
|
|||
|
|
@ -4864,7 +4864,6 @@
|
|||
"settings.personal.passkey.remove.button": "Remove passkey",
|
||||
"settings.personal.method.status.notSetUp": "Not set up",
|
||||
"settings.personal.method.button.setUp": "Set up",
|
||||
"settings.personal.method.button.switchTo": "Switch to this",
|
||||
"settings.personal.method.button.remove": "Remove",
|
||||
"settings.personal.method.button.disable": "Disable",
|
||||
"settings.personal.twoFactor.section.title": "Two-factor authentication (2FA)",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export async function verifyRegistration(
|
|||
id: string;
|
||||
credentialId: string;
|
||||
label: string;
|
||||
method: 'passkey' | 'security_key';
|
||||
}> {
|
||||
return await makeRestApiRequest(context, 'POST', '/mfa/webauthn/registration-verify', data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,11 +595,7 @@ onBeforeUnmount(() => {
|
|||
v-else
|
||||
variant="subtle"
|
||||
size="small"
|
||||
:label="
|
||||
has2fa
|
||||
? i18n.baseText('settings.personal.method.button.switchTo')
|
||||
: i18n.baseText('settings.personal.method.button.setUp')
|
||||
"
|
||||
:label="i18n.baseText('settings.personal.method.button.setUp')"
|
||||
:data-test-id="`mfa-method-${option.method}-setup`"
|
||||
@click="onTwoFactorMethodClick(option.method)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -444,7 +444,9 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
});
|
||||
if (currentUser.value) {
|
||||
currentUser.value.mfaEnabled = true;
|
||||
currentUser.value.mfaMethod = attachment === 'platform' ? 'passkey' : 'security_key';
|
||||
// Use the BE-classified method — the OS picker may route a
|
||||
// cross-platform request through a platform authenticator.
|
||||
currentUser.value.mfaMethod = result.method;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user