Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions src/main/resources/static/js/user/webauthn-register.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { getCsrfToken, getCsrfHeaderName, base64urlToBuffer, bufferToBase64url }
* Raised when passkey enrollment is refused because the session lacks a recent authentication (SUF-02).
*
* With step-up enabled the framework gates POST /webauthn/register on a factor issued within
* `enrollmentTtlSeconds`, enforced as an authorization rule that returns a plain 403 (not a
* `step-up-required` 401). Re-running the passkey ceremony cannot satisfy it: the user may have no passkey
* yet, and enrollment accepts any factor, so the remedy is a fresh login, not a ceremony retry.
* `enrollmentTtlSeconds`. Framework versions before 5.3.4 denied with a plain 403; 5.3.4+ denies with a
* 401 carrying error code `step-up-required` (StepUpEnrollmentAccessDeniedHandler), matching the sibling
* credential-management endpoints. Re-running the passkey ceremony cannot satisfy it either way: the user
* may have no passkey yet, and enrollment accepts any factor, so the remedy is a fresh login, not a
* ceremony retry.
*/
export class PasskeyEnrollmentStepUpError extends Error {
constructor() {
Expand Down Expand Up @@ -93,20 +95,23 @@ export async function registerPasskey(labelInput) {
});

if (!finishResponse.ok) {
// The enrollment step-up gate is an authorization rule, so a stale/factorless session is refused here
// with a bare 403 rather than the step-up-required 401 the other operations return. Surface it as its
// own error so the UI can tell the user to sign in again instead of offering a passkey retry.
if (finishResponse.status === 403) {
throw new PasskeyEnrollmentStepUpError();
}
// A stale/factorless session is refused by the enrollment step-up gate. Framework versions before
// 5.3.4 denied with a bare 403 (an authorization rule with no body); 5.3.4+ denies with a 401
// carrying error code "step-up-required". Recognize both, and surface it as its own error so the UI
// can tell the user to sign in again instead of offering a passkey retry.
let msg = 'Registration failed';
let errorCode;
try {
const data = await finishResponse.json();
msg = data.message || msg;
errorCode = data.error;
} catch {
const text = await finishResponse.text();
if (text) msg = text;
}
Comment on lines 102 to 111
if (finishResponse.status === 403 || (finishResponse.status === 401 && errorCode === 'step-up-required')) {
throw new PasskeyEnrollmentStepUpError();
}
throw new Error(msg);
}

Expand Down
Loading