# WebAuthn Platform Enrollment Skip Behavior

**URL:** <https://community.auth0.com/t/webauthn-platform-enrollment-skip-behavior/201542>\
**Category:** Get Help\
**Tags:** mfa-api, mfa\
**Created:** [July 10, 2026, 5:08pm UTC](https://community.auth0.com/t/webauthn-platform-enrollment-skip-behavior/201542 "2026-07-10T17:08:32Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![dhrupal.patel](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/dhrupal.patel/32/80019_2.png) [@dhrupal.patel](https://community.auth0.com/u/dhrupal.patel)\
**Post date:** [July 10, 2026, 5:08pm UTC](https://community.auth0.com/t/webauthn-platform-enrollment-skip-behavior/201542/1 "2026-07-10T17:08:32Z")

</div>

`snoozeEnrollment()` and `refuseEnrollmentOnThisDevice()` fail to complete transaction when enrollment is triggered via `api.authentication.enrollWith()` in a Post-Login Action

**Category:** Multi-factor Authentication / WebAuthn / Actions

\*\*Summary:\*\*When WebAuthn platform enrollment is triggered programmatically via `api.authentication.enrollWith({ type: 'webauthn-platform' })` in a Post-Login Action, neither `snoozeEnrollment()` nor `refuseEnrollmentOnThisDevice()` from the ACUL SDK are able to complete the login transaction when called from the Universal Login enrollment screen. Both methods result in the transaction failing and the user being unable to log in.

This appears to be because `enrollWith` creates a transaction context where Auth0 expects enrollment to be completed or explicitly refused at the policy level — but neither SDK method satisfies that requirement when enrollment is action-driven rather than policy-driven (progressive enrollment).

The only known workaround is calling `reportBrowserError()` with a synthetic error on skip, which signals a browser-side WebAuthn failure and allows Auth0 to continue the transaction without enrollment being completed. This suggests `snoozeEnrollment()` and `refuseEnrollmentOnThisDevice()` are only designed to work within Auth0’s native progressive enrollment flow, not action-triggered enrollment, and the documentation does not make this distinction clear.Ready to post? 🔎 First try searching for your answer.

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [July 10, 2026, 8:01pm UTC](https://community.auth0.com/t/webauthn-platform-enrollment-skip-behavior/201542/3 "2026-07-10T20:01:02Z")

</div>

Hi again @dhrupal.patel

I can see that you are experiencing similar issues posted in your previous topic regarding the skip behavior of the WebAuth enrollment. In order to address the more specific issues you have posted here:

You are reporting that when WebAuthn platform authenticator enrollment is triggered programmatically via `api.authentication.enrollWith({ type: 'webauthn-platform' })` in a Post-Login Action, neither `snoozeEnrollment()` nor `refuseEnrollmentOnThisDevice()` from the Advanced Customizations for Universal Login (ACUL) SDK can complete the login transaction. Both methods result in transaction failure and the user being unable to log in, and the only workaround is calling `reportBrowserError()` with a synthetic WebAuthn error to signal a browser-side failure.

**Root Cause:** Auth0 does not officially support optional MFA enrollment with skip or snooze functionality when enrollment is triggered via `api.authentication.enrollWith()` in a Post-Login Action. When `enrollWith()` is called, it creates a mandatory enrollment transaction that Auth0 expects to be completed before the authentication flow can proceed. The ACUL SDK methods `snoozeEnrollment()` and `refuseEnrollmentOnThisDevice()` are designed to work only within Auth0's native progressive enrollment flow (where enrollment is policy-driven), not with action-triggered enrollment. These methods do not satisfy the transaction completion requirement imposed by `enrollWith()`, leaving the transaction in a failed state.

The `reportBrowserError()` workaround succeeds because it signals a WebAuthn API failure at the browser level, which Auth0 interprets as a legitimate technical reason to bypass the enrollment requirement and allow the transaction to complete. This is not an intended use of the method and should not be relied upon as a permanent solution.

**Official Limitation:** According to Auth0 support documentation, skipping MFA enrollment is not supported when MFA is enabled. The platform requires that when an enrollment is triggered, it must be completed before authentication can proceed. There is no tenant-side configuration, Login Flow Action, or MFA enrollment policy setting that can change this behavior when using `enrollWith()`.

**Recommended Alternatives:**

1. **Use `enrollWithAny()` instead of `enrollWith()`** — This method allows users to skip enrollment if they already have at least one other MFA factor enrolled. If the user has no other factors, they are still required to enroll in one of the available options, but they can choose which factor to use. 

Example:

```
exports.onExecutePostLogin = async (event, api) => {
  if (event.user.enrolledFactors.length === 0) {
    api.authentication.enrollWithAny({ 
      factors: ['webauthn-platform', 'otp'] 
    });
  }
};
```

2. **Use conditional logic to avoid triggering enrollment for specific users** — Instead of calling `enrollWith()` for all users, check user metadata, group membership, or other conditions to determine whether enrollment should be prompted at all. 

Example:

```
exports.onExecutePostLogin = async (event, api) => {
  if (event.user.app_metadata.requiresWebAuthnEnrollment) {
    api.authentication.enrollWith({ 
      type: 'webauthn-platform' 
    });
  }
};
```

3. **Prompt users for enrollment outside the authentication flow** — Implement enrollment as an optional, post-login user preference in your application rather than as a mandatory step during authentication. This allows users to enroll at their own pace without blocking login.
4. **Use `tryAnotherMethod()` from the ACUL SDK** — If you are using a custom enrollment screen, the `tryAnotherMethod()` method allows users to switch to a different MFA factor, but this does not allow them to skip enrollment entirely.

**What the documentation does not clarify:** The ACUL SDK documentation for `snoozeEnrollment()` and `refuseEnrollmentOnThisDevice()` does not explicitly state that these methods only work with policy-driven progressive enrollment and will fail when enrollment is triggered via `api.authentication.enrollWith()` in a Post-Login Action. This distinction should be documented to prevent developers from attempting to use these methods in action-triggered scenarios where they are not supported.

**Submitting feedback:** If optional enrollment with skip/snooze functionality is required for your use case, Auth0 recommends submitting a feature request using the [Auth0 Product Feedback page](https://auth0.com/feedback).

**You might want to dig into these resources:**

- [Auth0 support article on making MFA enrollment optional](https://support.auth0.com/center/s/article/Is-it-Possible-to-Make-MFA-Enrollment-Optional)
- [Auth0 documentation on customizing MFA enrollments for Universal Login](https://auth0.com/docs/secure/multi-factor-authentication/customize-mfa/customize-mfa-enrollments-universal-login.md)
- [Auth0 support article on action-triggered MFA using enrollWith and challengeWith](https://support.auth0.com/center/s/article/Action-triggered-MFA-using-enrollWith-and-challengeWith)
- [Auth0 ACUL SDK documentation for MfaWebAuthnPlatformEnrollment](https://auth0.com/docs/libraries/acul/js-sdk/Screens/classes/MfaWebAuthnPlatformEnrollment.md)

We hope this clarifies the limitation and provides a path forward for your implementation.

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![dhrupal.patel](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/dhrupal.patel/32/80019_2.png) [@dhrupal.patel](https://community.auth0.com/u/dhrupal.patel)\
**Post date:** [July 14, 2026, 3:37pm UTC](https://community.auth0.com/t/webauthn-platform-enrollment-skip-behavior/201542/4 "2026-07-14T15:37:17Z")

</div>

## Biometrics Skip / MFA Completion — Investigation Synopsis

### Background

The member portal has a biometrics enrollment screen shown during the Auth0 Universal Login (UL) flow. This screen appears after email/phone MFA is satisfied and prompts the user to enroll in WebAuthn (biometrics) or skip. The requirement is that this screen always appears inside the UL flow so the user can enroll or consciously skip.

* * *

### The Core Problem

When a user clicks “Skip” on the biometrics enrollment screen, the app calls `snoozeEnrollment()` on the Auth0/UL side. This call completes successfully, but Auth0 then redirects back to the member portal with an **error in the URL hash** instead of an access token. The member portal’s `handleLoginResponse` in service.ts calls `auth0Client.parseHash()`, receives a non-null `err`, and treats it as a login failure — showing a login error screen instead of completing the login.

The user’s email/phone MFA was already satisfied before the biometrics screen appeared, so this is incorrect behavior — the login should complete successfully.

* * *

### What We Investigated (Dev)

**1. Where the error originates**

Added logging in `handleLoginResponse` to capture the raw `parseHash` error. The console showed:

```auto
[parseHash error] { error: 'server_error', errorDescription: undefined }

```

The full `error_description` was URL-encoded in the raw hash: `MFA was%20...` — Auth0-js was not surfacing it on the `err` object, so we parsed it directly from `window.location.hash`.

**2. Why `server_error` is returned**

The Auth0 Action (`mfaEnablement`) contains this block:

```auto
if ((isUniversalLoginFlow || isMobileUniversalLoginFlow) && !isEnrolledInBiometrics && isWebAuthnAvailable) {
    api.authentication.enrollWith({ type: 'webauthn-platform' });
} 

```

`enrollWith` makes biometric enrollment a **required step** in the Auth0 authorization flow. When `snoozeEnrollment()` is called to skip it, Auth0 considers a required step incomplete and cannot issue a token — so it redirects back with `server_error` instead.

**3. Client-side fallback via `checkSession`**

Added a guard in `handleLoginResponse` to detect the WebAuthn skip error and fall back to `checkSession` to silently retrieve a valid session token:

```auto
if (isMfaWebAuthnSkip) {
    auth0Client.checkSession({ prompt: 'none' }, (sessionErr, sessionResponse) => { ... });
} 

```

**Why it failed:** `checkSession` also failed. Because Auth0 returned `server_error`, it never established a session — there was nothing to retrieve. The client-side app cannot recover from a flow that Auth0 itself considers incomplete. The fix must be in the Auth0 Action.

* * *

### What We Tried in Prod

**Attempt 1: Disable biometrics via Auth0 dashboard (Security \> Multi-Factor Auth)**

Turning off WebAuthn in the Auth0 dashboard to see if removing it at the platform level would allow the flow to complete cleanly.

**What happened:** This caused a security issue screen to appear for users, breaking login entirely. Turned back on immediately.

**Attempt 2: Comment out the `enrollWith` line in the prod action**

With biometrics re-enabled in the dashboard, commented out just the `enrollWith` call in the action to see if the skip error would go away while keeping MFA intact.

**What happened:** The biometrics prompt disappeared as expected — but email/phone MFA also stopped being challenged. Users bypassed 2FA entirely. This suggests the presence of `enrollWith` in the flow is affecting how Auth0 sequences the MFA challenge + enrollment steps, not just controlling the enrollment screen itself.

* * *

### Why We Are Blocked

The fundamental conflict is:

- `enrollWith` makes biometrics a **mandatory** step in Auth0’s flow, which means skipping it causes `server_error` — unrecoverable client-side
- Removing it breaks the requirement that the screen appears in UL, and demonstrably breaks MFA challenge sequencing
- An alternative approach using `api.redirect.sendUserTo()` was considered — this would show the enrollment screen as a redirect step and resume the Auth0 flow via `/continue` whether the user enrolled or skipped. However, this would require refactoring multiple applications and may not ultimately solve the problem, making it not a viable path forward at this time
- No other Auth0-supported mechanism has been identified that allows an optional enrollment step inside the UL flow where skipping still results in a token being issued

* * *

### Current State

- Universal Login already has `snoozeEnrollment` wired up as intended
- Member portal changes (the `checkSession` fallback and associated logging) are sitting in a feature branch and have not been deployed — they are confirmed not to work and should be cleaned up before the branch is merged
- The prod Auth0 action is unchanged and restored to its original state
- The feature is blocked pending a viable solution for handling the skip case within the Auth0 action
