AuthRequestResponse notification incorrectly sent to approving device, causing duplicate notification on Android #2537

Open
opened 2026-02-20 08:18:37 -05:00 by deekerman · 0 comments
Owner

Originally created by @ivulit on GitHub (Feb 4, 2026).

Prerequisites

Vaultwarden Support String

Your environment (Generated via diagnostics page)

  • Vaultwarden version: v1.35.2
  • Web-vault version: v2025.12.1+build.3
  • OS/Arch: linux/x86_64
  • Running within a container: true (Base: Alpine)
  • Database type: SQLite
  • Database version: 3.51.1
  • Uses config.json: false
  • Uses a reverse proxy: true
  • IP Header check: true (X-Real-IP)
  • Internet access: true
  • Internet access via a proxy: false
  • DNS Check: true
  • TZ environment: Europe/Moscow
  • Browser/Server Time Check: true
  • Server/NTP Time Check: true
  • Domain Configuration Check: true
  • HTTPS Check: true
  • Websocket Check: true
  • HTTP Response Checks: true

Config & Details (Generated via diagnostics page)

Show Config & Details

Config:

{
  "_duo_akey": null,
  "_enable_duo": true,
  "_enable_email_2fa": true,
  "_enable_smtp": true,
  "_enable_yubico": true,
  "_icon_service_csp": "",
  "_icon_service_url": "",
  "_ip_header_enabled": true,
  "_max_note_size": 10000,
  "_smtp_img_src": "***:",
  "admin_ratelimit_max_burst": 3,
  "admin_ratelimit_seconds": 300,
  "admin_session_lifetime": 20,
  "admin_token": "***",
  "allowed_connect_src": "",
  "allowed_iframe_ancestors": "",
  "attachments_folder": "data/attachments",
  "auth_request_purge_schedule": "30 * * * * *",
  "authenticator_disable_time_drift": false,
  "data_folder": "data",
  "database_conn_init": "",
  "database_idle_timeout": 600,
  "database_max_conns": 10,
  "database_min_conns": 2,
  "database_timeout": 30,
  "database_url": "***************",
  "db_connection_retries": 15,
  "disable_2fa_remember": false,
  "disable_admin_token": false,
  "disable_icon_download": false,
  "dns_prefer_ipv6": false,
  "domain": "*****://***************",
  "domain_origin": "*****://***************",
  "domain_path": "",
  "domain_set": true,
  "duo_context_purge_schedule": "30 * * * * *",
  "duo_host": null,
  "duo_ikey": null,
  "duo_skey": null,
  "duo_use_iframe": false,
  "email_2fa_auto_fallback": false,
  "email_2fa_enforce_on_verified_invite": false,
  "email_attempts_limit": 3,
  "email_change_allowed": true,
  "email_expiration_time": 600,
  "email_token_size": 6,
  "emergency_access_allowed": true,
  "emergency_notification_reminder_schedule": "0 3 * * * *",
  "emergency_request_timeout_schedule": "0 7 * * * *",
  "enable_db_wal": true,
  "enable_websocket": true,
  "enforce_single_org_with_reset_pw_policy": false,
  "event_cleanup_schedule": "0 10 0 * * *",
  "events_days_retain": null,
  "experimental_client_feature_flags": "ssh-key-vault-item,ssh-agent,fido2-vault-credentials,inline-menu-positioning-improvements,inline-menu-totp,export-attachments,pm-25373-windows-biometrics-v2",
  "extended_logging": true,
  "helo_name": null,
  "hibp_api_key": null,
  "http_request_block_non_global_ips": true,
  "http_request_block_regex": "'\\.(local|arpa)$'",
  "icon_blacklist_non_global_ips": true,
  "icon_blacklist_regex": null,
  "icon_cache_folder": "data/icon_cache",
  "icon_cache_negttl": 21600,
  "icon_cache_ttl": 2592000,
  "icon_download_timeout": 30,
  "icon_redirect_code": 302,
  "icon_service": "internal",
  "incomplete_2fa_schedule": "30 * * * * *",
  "incomplete_2fa_time_limit": 3,
  "increase_note_size_limit": false,
  "invitation_expiration_hours": 120,
  "invitation_org_name": "Vaultwarden",
  "invitations_allowed": true,
  "ip_header": "X-Real-IP",
  "job_poll_interval_ms": 30000,
  "log_file": null,
  "log_level": "error",
  "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f",
  "login_ratelimit_max_burst": 10,
  "login_ratelimit_seconds": 60,
  "org_attachment_limit": null,
  "org_creation_users": "",
  "org_events_enabled": false,
  "org_groups_enabled": false,
  "password_hints_allowed": true,
  "password_iterations": 600000,
  "purge_incomplete_sso_auth": "0 20 0 * * *",
  "push_enabled": true,
  "push_identity_uri": "https://identity.bitwarden.com",
  "push_installation_id": "***",
  "push_installation_key": "***",
  "push_relay_uri": "https://push.bitwarden.com",
  "reload_templates": false,
  "require_device_email": false,
  "rsa_key_filename": "data/rsa_key",
  "send_purge_schedule": "0 5 * * * *",
  "sendmail_command": null,
  "sends_allowed": true,
  "sends_folder": "data/sends",
  "show_password_hint": false,
  "signups_allowed": false,
  "signups_domains_whitelist": "",
  "signups_verify": true,
  "signups_verify_resend_limit": 6,
  "signups_verify_resend_time": 3600,
  "smtp_accept_invalid_certs": false,
  "smtp_accept_invalid_hostnames": false,
  "smtp_auth_mechanism": "Login",
  "smtp_debug": false,
  "smtp_embed_images": true,
  "smtp_explicit_tls": null,
  "smtp_from": "*********************",
  "smtp_from_name": "***********",
  "smtp_host": "**************",
  "smtp_password": "***",
  "smtp_port": 465,
  "smtp_security": "force_tls",
  "smtp_ssl": null,
  "smtp_timeout": 15,
  "smtp_username": "***********",
  "sso_allow_unknown_email_verification": false,
  "sso_audience_trusted": null,
  "sso_auth_only_not_session": false,
  "sso_authority": "",
  "sso_authorize_extra_params": "",
  "sso_callback_path": "*****://********************************************",
  "sso_client_cache_expiration": 0,
  "sso_client_id": "",
  "sso_client_secret": "***",
  "sso_debug_tokens": false,
  "sso_enabled": false,
  "sso_master_password_policy": null,
  "sso_only": false,
  "sso_pkce": true,
  "sso_scopes": "email profile",
  "sso_signups_match_email": true,
  "templates_folder": "data/templates",
  "tmp_folder": "data/tmp",
  "trash_auto_delete_days": null,
  "trash_purge_schedule": "0 5 0 * * *",
  "use_sendmail": false,
  "use_syslog": false,
  "user_attachment_limit": null,
  "user_send_limit": null,
  "web_vault_enabled": true,
  "web_vault_folder": "web-vault/",
  "yubico_client_id": null,
  "yubico_secret_key": null,
  "yubico_server": null
}

Vaultwarden Build Version

1.35.2

Deployment method

Official Container Image

Custom deployment method

No response

Reverse Proxy

nginx 1.28.0

Host/Server Operating System

Linux

Operating System Version

Alpine Linux v3.23

Clients

Android

Client Version

Android 2026.1.0 (21141)

Steps To Reproduce

  1. Enable push notifications on the vaultwarden instance
  2. On Device A (e.g. browser), choose "Log in with device
  3. On Device B (Android), receive the AuthRequest push notification
  4. Tap the notification on Device B and approve the login request

Expected Result

Device B shows no further notifications after approval. Device A receives the approval and completes login

Actual Result

Device B receives an AuthRequestResponse (type 16) push notification immediately after approving, which appears as a duplicate auth request notification on Android.

Logs

[2026-01-24 11:02:32.978][response][INFO] (put_auth_request) PUT /api/auth-requests/<auth_request_id> => 200 OK
[2026-01-24 11:02:32.978][vaultwarden::api::push][DEBUG] Auth Push token still valid, no need for a new one
[2026-01-24 11:02:32.978][hyper_util::client::legacy::pool][TRACE] take? ("https", push.bitwarden.com): expiration = Some(90s)
[2026-01-24 11:02:32.978][hyper_util::client::legacy::pool][DEBUG] reuse idle connection for ("https", push.bitwarden.com)

Screenshots or Videos

No response

Additional Context

Analysis

In put_auth_request (src/api/core/accounts.rs:1591-1592), two notification calls are made after approval:

ant.send_auth_response(&auth_request.user_uuid, &auth_request.uuid).await;
nt.send_auth_response(&auth_request.user_uuid, &auth_request.uuid, &headers.device, &conn).await;

ant.send_auth_response() sends through the anonymous WebSocket hub, keyed by auth_request_id — this correctly reaches only Device A (the requesting device).

nt.send_auth_response() does two things:

  1. Sends through the authenticated WebSocket hub to all devices of the user (notifications.rs:523-524: self.send_update(user_id, &data))
  2. Sends a push notification via relay (notifications.rs:527-528)

Both reach Device B (the approving device), which should not receive AuthRequestResponse at all.

Official Bitwarden server behavior

In the official server, PushAuthRequestResponseAsync (IPushNotificationService.cs:387-399) creates a single PushNotification with ExcludeCurrentContext = true.
This notification is routed through all push engines:

  • SignalR (HubHelpers.cs:109-120): AuthRequestResponse is sent only through _anonymousHubContext to Group(AuthRequest.Id). It is not sent through the
    authenticated _hubContext. This is the key difference from AuthRequest (type 15), which is sent through _hubContext.Clients.User() (line 130).
  • Push relay (RelayPushEngine.cs:100): Identifier is set to the current device's identifier when ExcludeCurrentContext = true, and NotificationHubPushEngine
    (BuildTag, line 94) builds an exclusion tag !deviceIdentifier:{identifier}, preventing the push from reaching the approving device.

As a result, Device B receives nothing on the official server.


This analysis was conducted with the help of Claude (Anthropic).

Originally created by @ivulit on GitHub (Feb 4, 2026). ### Prerequisites - [x] I have searched the existing **Closed _AND_ Open** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=) - [x] I have searched and read the [documentation](https://github.com/dani-garcia/vaultwarden/wiki/) ### Vaultwarden Support String ### Your environment (Generated via diagnostics page) * Vaultwarden version: v1.35.2 * Web-vault version: v2025.12.1+build.3 * OS/Arch: linux/x86_64 * Running within a container: true (Base: Alpine) * Database type: SQLite * Database version: 3.51.1 * Uses config.json: false * Uses a reverse proxy: true * IP Header check: true (X-Real-IP) * Internet access: true * Internet access via a proxy: false * DNS Check: true * TZ environment: Europe/Moscow * Browser/Server Time Check: true * Server/NTP Time Check: true * Domain Configuration Check: true * HTTPS Check: true * Websocket Check: true * HTTP Response Checks: true ### Config & Details (Generated via diagnostics page) <details><summary>Show Config & Details</summary> **Config:** ```json { "_duo_akey": null, "_enable_duo": true, "_enable_email_2fa": true, "_enable_smtp": true, "_enable_yubico": true, "_icon_service_csp": "", "_icon_service_url": "", "_ip_header_enabled": true, "_max_note_size": 10000, "_smtp_img_src": "***:", "admin_ratelimit_max_burst": 3, "admin_ratelimit_seconds": 300, "admin_session_lifetime": 20, "admin_token": "***", "allowed_connect_src": "", "allowed_iframe_ancestors": "", "attachments_folder": "data/attachments", "auth_request_purge_schedule": "30 * * * * *", "authenticator_disable_time_drift": false, "data_folder": "data", "database_conn_init": "", "database_idle_timeout": 600, "database_max_conns": 10, "database_min_conns": 2, "database_timeout": 30, "database_url": "***************", "db_connection_retries": 15, "disable_2fa_remember": false, "disable_admin_token": false, "disable_icon_download": false, "dns_prefer_ipv6": false, "domain": "*****://***************", "domain_origin": "*****://***************", "domain_path": "", "domain_set": true, "duo_context_purge_schedule": "30 * * * * *", "duo_host": null, "duo_ikey": null, "duo_skey": null, "duo_use_iframe": false, "email_2fa_auto_fallback": false, "email_2fa_enforce_on_verified_invite": false, "email_attempts_limit": 3, "email_change_allowed": true, "email_expiration_time": 600, "email_token_size": 6, "emergency_access_allowed": true, "emergency_notification_reminder_schedule": "0 3 * * * *", "emergency_request_timeout_schedule": "0 7 * * * *", "enable_db_wal": true, "enable_websocket": true, "enforce_single_org_with_reset_pw_policy": false, "event_cleanup_schedule": "0 10 0 * * *", "events_days_retain": null, "experimental_client_feature_flags": "ssh-key-vault-item,ssh-agent,fido2-vault-credentials,inline-menu-positioning-improvements,inline-menu-totp,export-attachments,pm-25373-windows-biometrics-v2", "extended_logging": true, "helo_name": null, "hibp_api_key": null, "http_request_block_non_global_ips": true, "http_request_block_regex": "'\\.(local|arpa)$'", "icon_blacklist_non_global_ips": true, "icon_blacklist_regex": null, "icon_cache_folder": "data/icon_cache", "icon_cache_negttl": 21600, "icon_cache_ttl": 2592000, "icon_download_timeout": 30, "icon_redirect_code": 302, "icon_service": "internal", "incomplete_2fa_schedule": "30 * * * * *", "incomplete_2fa_time_limit": 3, "increase_note_size_limit": false, "invitation_expiration_hours": 120, "invitation_org_name": "Vaultwarden", "invitations_allowed": true, "ip_header": "X-Real-IP", "job_poll_interval_ms": 30000, "log_file": null, "log_level": "error", "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f", "login_ratelimit_max_burst": 10, "login_ratelimit_seconds": 60, "org_attachment_limit": null, "org_creation_users": "", "org_events_enabled": false, "org_groups_enabled": false, "password_hints_allowed": true, "password_iterations": 600000, "purge_incomplete_sso_auth": "0 20 0 * * *", "push_enabled": true, "push_identity_uri": "https://identity.bitwarden.com", "push_installation_id": "***", "push_installation_key": "***", "push_relay_uri": "https://push.bitwarden.com", "reload_templates": false, "require_device_email": false, "rsa_key_filename": "data/rsa_key", "send_purge_schedule": "0 5 * * * *", "sendmail_command": null, "sends_allowed": true, "sends_folder": "data/sends", "show_password_hint": false, "signups_allowed": false, "signups_domains_whitelist": "", "signups_verify": true, "signups_verify_resend_limit": 6, "signups_verify_resend_time": 3600, "smtp_accept_invalid_certs": false, "smtp_accept_invalid_hostnames": false, "smtp_auth_mechanism": "Login", "smtp_debug": false, "smtp_embed_images": true, "smtp_explicit_tls": null, "smtp_from": "*********************", "smtp_from_name": "***********", "smtp_host": "**************", "smtp_password": "***", "smtp_port": 465, "smtp_security": "force_tls", "smtp_ssl": null, "smtp_timeout": 15, "smtp_username": "***********", "sso_allow_unknown_email_verification": false, "sso_audience_trusted": null, "sso_auth_only_not_session": false, "sso_authority": "", "sso_authorize_extra_params": "", "sso_callback_path": "*****://********************************************", "sso_client_cache_expiration": 0, "sso_client_id": "", "sso_client_secret": "***", "sso_debug_tokens": false, "sso_enabled": false, "sso_master_password_policy": null, "sso_only": false, "sso_pkce": true, "sso_scopes": "email profile", "sso_signups_match_email": true, "templates_folder": "data/templates", "tmp_folder": "data/tmp", "trash_auto_delete_days": null, "trash_purge_schedule": "0 5 0 * * *", "use_sendmail": false, "use_syslog": false, "user_attachment_limit": null, "user_send_limit": null, "web_vault_enabled": true, "web_vault_folder": "web-vault/", "yubico_client_id": null, "yubico_secret_key": null, "yubico_server": null } ``` </details> ### Vaultwarden Build Version 1.35.2 ### Deployment method Official Container Image ### Custom deployment method _No response_ ### Reverse Proxy nginx 1.28.0 ### Host/Server Operating System Linux ### Operating System Version Alpine Linux v3.23 ### Clients Android ### Client Version Android 2026.1.0 (21141) ### Steps To Reproduce 1. Enable push notifications on the vaultwarden instance 2. On Device A (e.g. browser), choose "Log in with device 3. On Device B (Android), receive the AuthRequest push notification 4. Tap the notification on Device B and approve the login request ### Expected Result Device B shows no further notifications after approval. Device A receives the approval and completes login ### Actual Result Device B receives an AuthRequestResponse (type 16) push notification immediately after approving, which appears as a duplicate auth request notification on Android. ### Logs ```text [2026-01-24 11:02:32.978][response][INFO] (put_auth_request) PUT /api/auth-requests/<auth_request_id> => 200 OK [2026-01-24 11:02:32.978][vaultwarden::api::push][DEBUG] Auth Push token still valid, no need for a new one [2026-01-24 11:02:32.978][hyper_util::client::legacy::pool][TRACE] take? ("https", push.bitwarden.com): expiration = Some(90s) [2026-01-24 11:02:32.978][hyper_util::client::legacy::pool][DEBUG] reuse idle connection for ("https", push.bitwarden.com) ``` ### Screenshots or Videos _No response_ ### Additional Context **Analysis** In put_auth_request (src/api/core/accounts.rs:1591-1592), two notification calls are made after approval: ant.send_auth_response(&auth_request.user_uuid, &auth_request.uuid).await; nt.send_auth_response(&auth_request.user_uuid, &auth_request.uuid, &headers.device, &conn).await; ant.send_auth_response() sends through the anonymous WebSocket hub, keyed by auth_request_id — this correctly reaches only Device A (the requesting device). nt.send_auth_response() does two things: 1. Sends through the authenticated WebSocket hub to all devices of the user (notifications.rs:523-524: self.send_update(user_id, &data)) 2. Sends a push notification via relay (notifications.rs:527-528) Both reach Device B (the approving device), which should not receive AuthRequestResponse at all. **Official Bitwarden server behavior** In the official server, PushAuthRequestResponseAsync (IPushNotificationService.cs:387-399) creates a single PushNotification with ExcludeCurrentContext = true. This notification is routed through all push engines: - SignalR (HubHelpers.cs:109-120): AuthRequestResponse is sent only through _anonymousHubContext to Group(AuthRequest.Id). It is not sent through the authenticated _hubContext. This is the key difference from AuthRequest (type 15), which is sent through _hubContext.Clients.User() (line 130). - Push relay (RelayPushEngine.cs:100): Identifier is set to the current device's identifier when ExcludeCurrentContext = true, and NotificationHubPushEngine (BuildTag, line 94) builds an exclusion tag !deviceIdentifier:{identifier}, preventing the push from reaching the approving device. As a result, Device B receives nothing on the official server. --- This analysis was conducted with the help of Claude (Anthropic).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vaultwarden#2537
No description provided.