LayerZeroFault
passkey recovery Updated:

Android Credential Manager WebAuthn NotAllowedError & Lock Fix

VV

Written by

Updated:

Technical Guide

To resolve Android Credential Manager WebAuthn NotAllowedError & Lock Fix, fix Android Credential Manager NotAllowedError and. Ensure all derivation paths, environment parameters, and cryptographic signatures are verified client-side using deterministic tools before broadcasting live transactions.

The Android Credential Manager DOMException: NotAllowedError and system prompt Authentication needed: Enter device password or unlock occur during WebAuthn passkey ceremonies when: (1) Android KeyStore enters biometric lockout after repeated sensor failures, (2) an embedded WebView lacks two-way assetlinks.json verification, or (3) the Relying Party ID (rpId) mismatches the origin. Unlocking the phone with the device Master PIN resets the biometric failure counter, while launching via Chrome Custom Tabs prevents WebView origin blocks.

To test your WebAuthn client parameters, origins, and challenge encoding offline, utilize our interactive WebAuthn Passkey Debugger Tool. For related mobile and desktop authentication failures, consult our Coinbase Desktop Passkey Bluetooth Fix and WebAuthn AbortError in Conditional UI.

1. Root Cause Architecture: How Credential Manager Validates Requests

Under Android 14+, when a Web3 webpage invokes navigator.credentials.create() or navigator.credentials.get(), Chrome does not talk directly to the Linux kernel or hardware secure element. Instead, it delegates the ceremony to Google Play Services Credential Manager:

$$\text{Web Page} \xrightarrow{\text{WebAuthn}} \text{Blink / Chrome} \xrightarrow{\text{IPC}} \text{Credential Manager} \xrightarrow{\text{Biometrics}} \text{TEE / StrongBox Keymaster}$$

The subsystem strictly enforces three validation gates. If any gate fails, Credential Manager aborts execution and dispatches NotAllowedError:

If the ceremony originates from a native Android app embedding a WebView (e.g., a mobile crypto wallet with a built-in browser), Android checks whether the app has established cryptographic ownership over the web domain (rpId). Without an active assetlinks.json verification, the OS considers the WebView an untrusted phishing vector and terminates the ceremony.

Gate 2: Biometric Enclave Lockout Counter

If a user fails fingerprint or facial recognition 5 consecutive times across any application, Android’s KeyguardManager trips an enclave lockout. Subsequent WebAuthn requests are denied automatically without prompting the user, returning NotAllowedError.

Gate 3: WebAuthn Challenge Expiration & Window Focus

The Android system enforces an internal 60-second challenge timeout. If an app performs heavy asynchronous cryptographic work (such as generating zero-knowledge proofs or fetching bundler pre-verification gas limits) before prompting the user, the server challenge expires, leading to an immediate timeout abort.

(For related browser-level cancellation anomalies, see our companion article on WebAuthn AbortError in Passkey Conditional UI).

2. Step-by-Step Resolution Protocols

Protocol 1: Fix Android Hybrid & WebView Environments

If you are developing a mobile app using React Native, Flutter, or native Kotlin/Java that displays your Web3 dApp:

  1. Do not use raw android.webkit.WebView for passkey auth. Raw WebViews do not pass origin credentials to Credential Manager.
  2. Implement Chrome Custom Tabs (CCT) or Android Custom Tabs: CCT shares the user’s system Chrome session, Google Password Manager, and Passkey enclave.

In React Native:

import * as WebBrowser from 'expo-web-browser';

// Launch passkey onboarding via Chrome Custom Tab instead of internal WebView
export async function openSecurePasskeyAuth(authUrl: string) {
  const result = await WebBrowser.openAuthSessionAsync(authUrl, 'myapp://callback');
  return result;
}
  1. Deploy Digital Asset Links: If you must use WebAuthn in an app that you own, deploy /.well-known/assetlinks.json on your web server’s root:
[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls",
      "delegate_permission/common.get_login_creds"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.layerzerofault.wallet",
      "sha256_cert_fingerprints": [
        "14:6D:E9:7D:0F:52:CC:77:47:31:6E:86:E5:43:CD:28:B4:97:54:15:3A:42:F3:11:DF:E0:BC:23:45:67:89:AB"
      ]
    }
  }
]

Protocol 2: Web3 Frontend Defensive Retry Pattern

In your web application, intercept NotAllowedError and differentiate between a deliberate user cancellation and an OS-level lockout:

export async function authenticatePasskeyWithFallback(
  options: CredentialRequestOptions
): Promise<Credential | null> {
  const startTime = Date.now();

  try {
    const credential = await navigator.credentials.get(options);
    return credential;
  } catch (err: unknown) {
    if (err instanceof DOMException && err.name === 'NotAllowedError') {
      const elapsed = Date.now() - startTime;

      // If the error returns in less than 250ms, the OS rejected the call before the user saw it!
      if (elapsed < 250) {
        console.warn('Android Credential Manager instant lockout detected.');
        throw new Error(
          'Biometric hardware locked or unauthorized WebView detected. Please unlock your device with your phone PIN or open this page in Chrome directly.'
        );
      } else {
        // User saw the prompt and manually tapped "Cancel"
        throw new Error('Authentication cancelled by user.');
      }
    }
    throw err;
  }
}

Protocol 3: End-User Quick-Fix for Biometric Lockout

If you are an end-user stuck in a NotAllowedError loop on Android:

  1. Force a PIN / Pattern Lock:
    • Turn off your phone screen using the physical power button.
    • Wake the screen and swipe to unlock.
    • Do not use fingerprint or face unlock; enter your device PIN or password directly. This resets Android’s Keyguard failure counter.
  2. Verify Google Play Services Updates:
    • Open Settings > Security & Privacy > System & Updates > Google Play system update.
    • Install pending updates to ensure Credential Manager has the latest FIDO2 patches.
  3. Open in Native Chrome:
    • If attempting to sign inside Telegram or Twitter, tap the three vertical dots ⋮ in the top-right corner and select Open in Chrome.

3. Summary Diagnostic Checklist

  • Verify that rpId matches the second-level domain (e.g., layerzerofault.site instead of sub-paths).
  • Verify that the server challenge has not timed out before navigator.credentials.get() is invoked.
  • Ensure mobile applications launch Chrome Custom Tabs rather than sandboxed WebViews.
  • Confirm that /.well-known/assetlinks.json returns HTTP 200 with Content-Type application/json.
Interactive Diagnostic Sandbox

Local WebAuthn & Smart Account Sandboxes

Debug WebAuthn credential requests, PRF extensions, and simulate ERC-4337 passkey account validation in client WebCrypto.

Companion Diagnostic Guide WebAuthn Conditional Mediation AbortError & Autofill Lock Fix →

Resolve WebAuthn AbortError and autofill UI locks in conditional passkey requests. Manage AbortController signals, avoid race conditions, and restore prompts.

Read Guide
Contextual Architecture

Related Diagnostic Guides

View All in Silo →

Related Inquiries

Why does Android Credential Manager throw 'NotAllowedError: The operation either timed out or was not allowed by the user'?

On Android 14 and 15, the Google Credential Manager API handles all FIDO2/WebAuthn ceremonies. A NotAllowedError triggers when: (1) the user cancels the prompt, (2) the secure enclave locks biometrics following five failed face/fingerprint attempts, (3) an embedded WebView lacks Digital Asset Links (assetlinks.json) verification, or (4) the Relying Party ID (rpId) does not match the verified origin.

What does 'Authentication needed: Enter device password or unlock' mean?

This Android system prompt appears when biometric authentication is temporarily locked by Keyguard after multiple failed attempts, or when the passkey requires elevated user verification. Unlocking your phone using your master device PIN, pattern, or password resets the biometric failure counter and re-enables passkey ceremonies.

Why do Web3 embedded wallets like Privy and Turnkey fail inside Android mobile apps?

Standard Android WebViews block WebAuthn calls by default or report origin as 'null' or 'android-app://<package_name>'. Unless the mobile wrapper implements Chrome Custom Tabs or declares a two-way assetlinks.json association, Credential Manager rejects the assertion with NotAllowedError.

How do I debug WebAuthn clientDataJSON and passkey parameters?

Use our interactive WebAuthn Passkey Debugger tool to inspect clientDataJSON, challenge bytes, origin strings, and rpId validation parameters in real time.