[GH-ISSUE #1471] 2FA error response does not match bitwarden/server #971

Closed
opened 2026-03-03 02:05:11 +03:00 by kerem · 1 comment
Owner

Originally created by @fugkco on GitHub (Mar 8, 2021).
Original GitHub issue: https://github.com/dani-garcia/vaultwarden/issues/1471

Subject of the issue

When attempting to do a login to an account that has 2FA enabled, but without the 2FA details, it seems to return the wrong error response. Not just the message, but the whole object is different. I understand that this is likely not a priority considering everything works, but for parity's sake, it would be nice to have this implemented the right way.

I also noticed the MFA token gets cast to u64, which means zeros at the beginning of the token get stripped. I'm not entirely sure if this is an issue but figured it's worth pointing out.

Deployment environment

Your environment (Generated via diagnostics page)

  • Bitwarden_rs version: v1.19.0
  • Web-vault version: v2.18.1
  • Running within Docker: true
  • Internet access: true
  • Uses a proxy: false
  • DNS Check: true
  • Time Check: true
  • Domain Configuration Check: false
  • HTTPS Check: false
  • Database type: SQLite
  • Clients used:
  • Reverse proxy and version:
  • Other relevant information:

Config (Generated via diagnostics page)

{
  "_duo_akey": null,
  "_enable_duo": false,
  "_enable_email_2fa": false,
  "_enable_smtp": true,
  "_enable_yubico": true,
  "_ip_header_enabled": true,
  "admin_token": "***",
  "allowed_iframe_ancestors": "",
  "attachments_folder": "data/attachments",
  "authenticator_disable_time_drift": false,
  "data_folder": "data",
  "database_max_conns": 10,
  "database_url": "****/**.*******",
  "db_connection_retries": 15,
  "disable_2fa_remember": false,
  "disable_admin_token": false,
  "disable_icon_download": false,
  "domain": "****://*********",
  "domain_origin": "****://*********",
  "domain_path": "",
  "domain_set": false,
  "duo_host": null,
  "duo_ikey": null,
  "duo_skey": null,
  "email_attempts_limit": 3,
  "email_expiration_time": 600,
  "email_token_size": 6,
  "enable_db_wal": true,
  "extended_logging": true,
  "helo_name": null,
  "hibp_api_key": null,
  "icon_blacklist_non_global_ips": true,
  "icon_blacklist_regex": null,
  "icon_cache_folder": "data/icon_cache",
  "icon_cache_negttl": 259200,
  "icon_cache_ttl": 2592000,
  "icon_download_timeout": 10,
  "invitation_org_name": "Bitwarden_RS",
  "invitations_allowed": true,
  "ip_header": "X-Real-IP",
  "log_file": null,
  "log_level": "Info",
  "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f",
  "org_attachment_limit": null,
  "org_creation_users": "",
  "password_iterations": 100000,
  "reload_templates": false,
  "require_device_email": false,
  "rsa_key_filename": "data/rsa_key",
  "show_password_hint": true,
  "signups_allowed": true,
  "signups_domains_whitelist": "",
  "signups_verify": false,
  "signups_verify_resend_limit": 6,
  "signups_verify_resend_time": 3600,
  "smtp_accept_invalid_certs": false,
  "smtp_accept_invalid_hostnames": false,
  "smtp_auth_mechanism": null,
  "smtp_debug": false,
  "smtp_explicit_tls": false,
  "smtp_from": "",
  "smtp_from_name": "Bitwarden_RS",
  "smtp_host": null,
  "smtp_password": null,
  "smtp_port": 587,
  "smtp_ssl": true,
  "smtp_timeout": 15,
  "smtp_username": null,
  "templates_folder": "data/templates",
  "use_syslog": false,
  "user_attachment_limit": null,
  "web_vault_enabled": true,
  "web_vault_folder": "web-vault/",
  "websocket_address": "0.0.0.0",
  "websocket_enabled": false,
  "websocket_port": 3012,
  "yubico_client_id": null,
  "yubico_secret_key": null,
  "yubico_server": null
}

Steps to reproduce

  1. Create a dummy user in Bitwarden RS, and enable any MFA type.
  2. Use the API to login (prelogin, then login) but do not specify the MFA token.
  3. Observe the error output
  4. Repeat steps 1 and 2 vault.bitwarden.com
  5. Compare error output from step 4 with error output from step 2.

Expected behaviour

{
  "error": "invalid_grant",
  "error_description": "Two factor required.",
  "TwoFactorProviders": ["0"],
  "TwoFactorProviders2": {"0": null}
}

Actual behaviour

Error response is as follows

{
  "ErrorModel": {
    "Message": "TOTP code is not a number",
    "Object": "error"
  },
  "Message": "",
  "Object":"error",
  "ValidationErrors": {
    "": ["TOTP code is not a number"]
  },
  "error": "",
  "error_description":""
}

Troubleshooting data

Originally created by @fugkco on GitHub (Mar 8, 2021). Original GitHub issue: https://github.com/dani-garcia/vaultwarden/issues/1471 ### Subject of the issue When attempting to do a login to an account that has 2FA enabled, but without the 2FA details, it seems to return the wrong error response. Not just the message, but the whole object is different. I understand that this is likely not a priority considering everything works, but for parity's sake, it would be nice to have this implemented the right way. I also noticed the [MFA token gets cast to u64](https://github.com/dani-garcia/bitwarden_rs/blob/master/src/api/core/two_factor/authenticator.rs#L116), which means zeros at the beginning of the token get stripped. I'm not entirely sure if this is an issue but figured it's worth pointing out. ### Deployment environment ### Your environment (Generated via diagnostics page) * Bitwarden_rs version: v1.19.0 * Web-vault version: v2.18.1 * Running within Docker: true * Internet access: true * Uses a proxy: false * DNS Check: true * Time Check: true * Domain Configuration Check: false * HTTPS Check: false * Database type: SQLite * Clients used: * Reverse proxy and version: * Other relevant information: ### Config (Generated via diagnostics page) ```json { "_duo_akey": null, "_enable_duo": false, "_enable_email_2fa": false, "_enable_smtp": true, "_enable_yubico": true, "_ip_header_enabled": true, "admin_token": "***", "allowed_iframe_ancestors": "", "attachments_folder": "data/attachments", "authenticator_disable_time_drift": false, "data_folder": "data", "database_max_conns": 10, "database_url": "****/**.*******", "db_connection_retries": 15, "disable_2fa_remember": false, "disable_admin_token": false, "disable_icon_download": false, "domain": "****://*********", "domain_origin": "****://*********", "domain_path": "", "domain_set": false, "duo_host": null, "duo_ikey": null, "duo_skey": null, "email_attempts_limit": 3, "email_expiration_time": 600, "email_token_size": 6, "enable_db_wal": true, "extended_logging": true, "helo_name": null, "hibp_api_key": null, "icon_blacklist_non_global_ips": true, "icon_blacklist_regex": null, "icon_cache_folder": "data/icon_cache", "icon_cache_negttl": 259200, "icon_cache_ttl": 2592000, "icon_download_timeout": 10, "invitation_org_name": "Bitwarden_RS", "invitations_allowed": true, "ip_header": "X-Real-IP", "log_file": null, "log_level": "Info", "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f", "org_attachment_limit": null, "org_creation_users": "", "password_iterations": 100000, "reload_templates": false, "require_device_email": false, "rsa_key_filename": "data/rsa_key", "show_password_hint": true, "signups_allowed": true, "signups_domains_whitelist": "", "signups_verify": false, "signups_verify_resend_limit": 6, "signups_verify_resend_time": 3600, "smtp_accept_invalid_certs": false, "smtp_accept_invalid_hostnames": false, "smtp_auth_mechanism": null, "smtp_debug": false, "smtp_explicit_tls": false, "smtp_from": "", "smtp_from_name": "Bitwarden_RS", "smtp_host": null, "smtp_password": null, "smtp_port": 587, "smtp_ssl": true, "smtp_timeout": 15, "smtp_username": null, "templates_folder": "data/templates", "use_syslog": false, "user_attachment_limit": null, "web_vault_enabled": true, "web_vault_folder": "web-vault/", "websocket_address": "0.0.0.0", "websocket_enabled": false, "websocket_port": 3012, "yubico_client_id": null, "yubico_secret_key": null, "yubico_server": null } ``` ### Steps to reproduce 1. Create a dummy user in Bitwarden RS, and enable any MFA type. 2. Use the API to login (`prelogin`, then `login`) but do not specify the MFA token. 3. Observe the error output 4. Repeat steps 1 and 2 `vault.bitwarden.com` 5. Compare error output from step 4 with error output from step 2. ### Expected behaviour ```json { "error": "invalid_grant", "error_description": "Two factor required.", "TwoFactorProviders": ["0"], "TwoFactorProviders2": {"0": null} } ``` ### Actual behaviour Error response is as follows ``` { "ErrorModel": { "Message": "TOTP code is not a number", "Object": "error" }, "Message": "", "Object":"error", "ValidationErrors": { "": ["TOTP code is not a number"] }, "error": "", "error_description":"" } ``` ### Troubleshooting data <!-- Share any log files, screenshots, or other relevant troubleshooting data -->
kerem 2026-03-03 02:05:11 +03:00
  • closed this issue
  • added the
    question
    label
Author
Owner

@BlackDex commented on GitHub (Jun 21, 2021):

I just checked the code, and verified it with upstream, but it looks like it produces the exact same response for me.
That error message you provided above only happens if you provide the twoFactorToken* variables during the request.
I also get the same kind of response on upstream.

So the order is as follows (for both upstream and vaultwarden).

  1. Login using username and password.
  2. Both return the Expected behaviour json and you are presented with a form to fill-in your MFA.
  3. If you type in anything invalid, like an empty string, or letters both will return the json you provided in the Actual behaviour, though VaultWarden and Bitwarden have a different layout, the message still shows in a red toast at the top right.

I think there is nothing wrong with the implementation on the Vaultwarden side.
Could you try and verify it again? And keep in mind to exclude the twoFactorToken* variables (or include them in both tries).

<!-- gh-comment-id:865227064 --> @BlackDex commented on GitHub (Jun 21, 2021): I just checked the code, and verified it with upstream, but it looks like it produces the exact same response for me. That error message you provided above only happens if you provide the `twoFactorToken*` variables during the request. I also get the same kind of response on upstream. So the order is as follows (for both upstream and vaultwarden). 1. Login using username and password. 2. Both return the `Expected behaviour` json and you are presented with a form to fill-in your MFA. 3. If you type in anything invalid, like an empty string, or letters both will return the json you provided in the `Actual behaviour`, though VaultWarden and Bitwarden have a different layout, the message still shows in a red toast at the top right. I think there is nothing wrong with the implementation on the Vaultwarden side. Could you try and verify it again? And keep in mind to exclude the `twoFactorToken*` variables (or include them in both tries).
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#971
No description provided.