Drupal is a registered trademark of Dries Buytaert

wa

18 sites Security covered
View on drupal.org

About the Module

The WebAuthn (passkey) module enables passwordless authentication for Drupal using Passkeys (FIDO2/WebAuthn). It allows users to register authenticators (such as Touch ID, Face ID, YubiKeys, or Windows Hello) and log in securely without entering a password.

The module leverages the robust web-auth/webauthn-lib library to handle cryptographic operations, ensuring a secure and standard-compliant implementation.

Features

  • Passwordless Login: Users can log in using only their passkey.
  • Secure Registration: Supports registration of multiple authenticators per user.
  • Configuration Control:
    • Global Toggle: Administrators can enable or disable passkey login globally.
    • Role Restrictions: Restrict passkey usage to specific user roles.
  • Management Interface: Users can view and delete their registered passkeys via a dedicated "Manage Passkeys" tab on their profile.
  • Email Notifications: Automatically sends email notifications to users when a new passkey is added to their account, providing an additional security layer by alerting them of any authentication changes.
  • Service Ticket System: Generates unique ticket IDs for errors during passkey operations, allowing for easier troubleshooting and support.
  • Security:
    • Flood Control: Protects against brute-force attacks on registration and login endpoints.
    • Origin Validation: Strictly validates the origin of authentication requests.
    • CSRF Protection: Secures sensitive management actions.
    • Authenticator Whitelisting:Only trusted, certified, or policy-approved authenticators can be enrolled or used for authentication. An admin can administer the whitelist.
    • Full action log: All actions and errors related to WehAuthn are logged in a dedicated Drupal log channel called wa.

Requirements

  • Drupal: ^11.2
  • PHP: ^8.3
  • Library: web-auth/webauthn-lib ^5.2
  • HTTPS: WebAuthn requires a secure context (HTTPS) to function. It will not work over HTTP (except for localhost).

Installation

Install the module via Composer to ensure all dependencies are downloaded:

composer require drupal/wa
drush en wa

Configuration

1. General Settings

Navigate to Configuration > People > Passkey Settings
(/admin/config/people/wa).

  • Enable Passkey Login: Toggle this off to disable the "Sign in with Passkey" button and block all passkey API endpoints.
  • Allowed Roles: Select which user roles are permitted to use passkeys. If no roles are selected, no users can use passkeys.
  • Allowed Authenticators: Select which authenticator types (by AAGUID) are permitted. Common options include YubiKey, Touch ID, Windows Hello, and Generic/Software Authenticators. If no authenticators are selected, no types are allowed (deny-all default).
  • Additional AAGUIDs: To whitelist a specific authenticator not in the default list, enter its AAGUID (one per line) in lowercase UUID format (e.g., 00000000-0000-0000-0000-000000000000). You can find AAGUIDs in the Drupal logs after a registration attempt or by consulting the FIDO Alliance Metadata Service.
  • User Verification: Choose whether user verification (PIN, biometric) is "Preferred" (default) or "Required" for login.
  • Resident Key Requirement: Controls whether the authenticator must create a client-side discoverable credential (resident key). Options include:
    1. Discouraged: Server stores the key handle; saves storage space on hardware keys but requires entering a username first.
    2. Preferred (default): Attempts to create a resident key when possible.
    3. Required: Forces resident key creation; necessary for the "Sign in with Passkey" button (usernameless login) to work.
  • Enforce User Handle Validation: When enabled, login will fail if the authenticator doesn't provide a user handle. Disable this if you encounter compatibility issues with older devices.
  • Send Email Notification on Passkey Addition: When enabled, users will receive an email notification whenever a new passkey is added to their account. This provides an additional security layer by alerting users of authentication changes. The email template can be customised with Drupal tokens.

2. Permissions

Configure permissions at /admin/people/permissions:

  • administer all user passkey: Allows administrators to manage (delete) passkeys for other users.

3. Passkey Overview

Administrators can view a list of all registered passkeys on the site by navigating to Administration > People > Passkeys (/admin/people/passkeys). This view provides details
such as:

  • User: The owner of the passkey.
  • Provider: The authenticator type/provider (e.g., Touch ID, YubiKey).
  • Created: The date and time of registration.
  • Last used: The last time the passkey was used for authentication.

4. User Passkey Management

Users can manage their own passkeys via their user profile:

  1. Go to My account (/user).
  2. Click on the Passkeys tab.
  3. Here, users can:
    • Add Passkey: Register a new device (Touch ID, YubiKey, etc.).
    • Delete: Remove an existing passkey.

Troubleshooting

"Sign in with Passkey" button is missing

  • Check if the module is enabled.
  • Check if Enable Passkey Login is checked in the configuration.
  • Ensure you are on the default user login form.

Rate limiting blocks requests unexpectedly

  • Flood control in this module keys on client IP for both options and verify endpoints. If you're behind a load balancer or proxy, ensure Drupal is configured for reverse proxy handling so `getClientIp()` resolves the real client IP: set `reverse_proxy` to `TRUE` and list proxy addresses/ranges in `reverse_proxy_addresses` (and trusted headers) in `settings.php`. See the Drupal's guidance for reverse proxies.

Registration/Login fails immediately

  • HTTPS: Ensure you are accessing the site over HTTPS. Browsers block WebAuthn API on insecure origins.
  • Console Errors: Check the browser's developer console for JavaScript errors.
  • Drupal Logs: Check Reports > Recent log messages for server-side errors ("wa" channel).

"The operation either timed out or was not allowed"

  • This is a browser-level error. It often happens if the user cancels the dialog or if the device doesn't support the requested authenticator type.

"This authenticator is not allowed for passkey login."

  • This error appears when adding a new passkey, and there is an error "Passkey registration blocked for disallowed AAGUID" in the Drupal logs if you have configured Allowed authenticators in the settings and the user is trying to use a restricted device.
  • Solution: Go to /admin/config/people/wa and ensure the authenticator type (AAGUID) is checked.
  • Firefox/Chrome/iCloud: If using a software authenticator (like Touch ID on Mac via Chrome/Firefox), ensure "Generic / Software Authenticator" is checked.

Clock Synchronization

  • WebAuthn relies on time-sensitive challenges. Ensure your server's clock is synchronized (NTP).

Login fails with "User handle is required by policy"

  • This error occurs if Enforce User Handle Validation is enabled in the configuration, but the user's authenticator (or browser) did not send the userHandle in the assertion response.
  • Cause: Some older authenticators or specific browser/OS combinations (e.g., some Android devices or older Chrome versions) may not return the user handle during login.
  • Solution: If your users encounter this, disable Enforce User Handle Validation in /admin/config/people/wa. This relaxes the check while maintaining standard security.

Known Issues

Interaction with other login modules (Redirects)

This module uses an AJAX-based login flow. If other modules (e.g., login_destination, user_redirect) attempt to redirect the user during login (via hook_user_login), this module catches the redirect and passes the target URL to the client-side JavaScript, which then performs the navigation.
For example, Authentication seems to fail when Drupal redirects in response to a login, which has been supposed to be fixed with Beta 3.

  • Impact: Most standard redirects work seamlessly. However, if a module relies on complex response manipulation (beyond simple redirects or cookies) during the login hook, it might not function as expected.
  • Workaround: The module explicitly handles EnforcedResponseException to support these flows.

2.0 New features

New Hook: hook_wa_login

A new hook hook_wa_login has been introduced to allow other modules to intervene during the passkey login process. This hook is invoked after the passkey has been successfully verified but before the user is fully logged in.

Usage:

Modules can implement this hook to:

  • Perform additional security checks (e.g., check IP allowlists, time of day).
  • Prevent login by setting allowed_login to FALSE.
  • Redirect the user to a secondary verification page (e.g., OTP, TFA) by providing a redirect_url.

Example:

function mymodule_wa_login(\Drupal\user\UserInterface $user) {
  // Check strict IP policy.
  if (!in_array(\Drupal::request()->getClientIp(), ['127.0.0.1'])) {
    return [[
      'allowed_login' => FALSE,
      'redirect_url' => Url::fromRoute('system.403')->toString(),
    ]];
  }
}

New Sub-module: WA Email OTP (wa_email_otp)

The wa module now ships with a submodule called wa_email_otp. This module demonstrates the power of the new hook_wa_login by implementing an Email One-Time Password (OTP) verification step after passkey authentication.

Features:

  • Step-up Authentication: Adds a second layer of security by requiring an email OTP after the passkey check.
  • Session Binding: securely binds the OTP session to the authenticated user to prevent replay attacks or link sharing.
  • Configurable Email: Administrators can customize the OTP email subject and body via the settings form.
  • Flood Control: Built-in flood control to prevent brute-force attacks on the OTP entry form.

Activity

Total releases
24
First release
Nov 2025
Latest release
2 days ago
Release cadence
4 days
Stability
0% stable

Release Timeline

Releases

Version Type Release date
2.0.0-rc5 Pre-release Mar 1, 2026
2.0.0-rc4 Pre-release Jan 23, 2026
2.0.0-rc3 Pre-release Jan 14, 2026
2.0.0-rc2 Pre-release Jan 5, 2026
2.0.0-rc1 Pre-release Jan 5, 2026
2.0.0-beta3 Pre-release Dec 18, 2025
2.0.0-beta2 Pre-release Dec 18, 2025
2.0.0-beta1 Pre-release Dec 17, 2025
2.0.0-alpha3 Pre-release Dec 16, 2025
1.0.0-beta9 Pre-release Dec 15, 2025
2.0.0-alpha2 Pre-release Dec 15, 2025
2.0.0-alpha1 Pre-release Dec 7, 2025
2.0.x-dev Dev Dec 7, 2025
1.0.0-beta8 Pre-release Nov 29, 2025
1.0.0-beta7 Pre-release Nov 29, 2025
1.0.0-beta6 Pre-release Nov 28, 2025
1.0.0-beta5 Pre-release Nov 28, 2025
1.0.0-beta4 Pre-release Nov 27, 2025
1.0.0-beta3 Pre-release Nov 24, 2025
1.0.0-beta2 Pre-release Nov 23, 2025
1.0.0-beta1 Pre-release Nov 22, 2025
1.0.0-alpha2 Pre-release Nov 22, 2025
1.0.0-alpha1 Pre-release Nov 21, 2025
1.0.x-dev Dev Nov 21, 2025