Skip to content

Organization invite links cannot be accepted in 1.37.0: web-vault requires initOrganization, send_invite never sends it #7481

Description

@vikfox

Prerequisites

Vaultwarden Support String

Your environment (Generated via diagnostics page)

  • Vaultwarden version: v1.37.0
  • Web-vault version: v2026.6.4
  • OS/Arch: linux/x86_64
  • Running within a container: true (Base: Debian)
  • Database type: SQLite
  • Database version: 3.51.3
  • Uses config.json: false
  • Uses a reverse proxy: true
  • IP Header check: false (X-Forwarded-For)
  • Internet access: true
  • Internet access via a proxy: false
  • DNS Check: true
  • 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:

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

Vaultwarden Build Version

1.37.0

Deployment method

Official Container Image

Custom deployment method

No response

Reverse Proxy

Caddy 2.10.2

Host/Server Operating System

Linux

Operating System Version

Ubuntu, Docker 29.x

Clients

Web Vault

Client Version

2026.6.4 (bundled with the 1.37.0 image)

Steps To Reproduce

  1. Run vaultwarden/server:1.37.0 with working SMTP (mail_enabled = true).
  2. Create an organization, then Members -> Invite a user by e-mail.
  3. Open the "Join Organization Now" link from the invitation e-mail, either in
    a clean browser session or while logged in as the invited user.

The web vault shows the toast "Unable to accept invitation. Ask an organization
admin to send a new invitation", and the membership stays in Invited state.

Important: no request reaches the server at all. With LOG_LEVEL=debug the log
shows only static asset requests - there is no
POST /api/organizations/<org_id>/users/<member_id>/accept

Expected Result

The invitation link generated by Vaultwarden's own e-mail should be accepted
by the web vault bundled in the same image, moving the membership to Accepted.

Actual Result

The link is rejected client-side before any API call, because the server and
the bundled web vault disagree on the required query parameters.

Server - src/mail.rs, send_invite():

query_params
    .append_pair("email", &user.email)
    .append_pair("organizationName", org_name)
    .append_pair("organizationId", &org_id)
    .append_pair("organizationUserId", &member_id)
    .append_pair("token", &invite_token);

if CONFIG.sso_enabled() && CONFIG.sso_only() {
    query_params.append_pair("orgSsoIdentifier", &org_id);
}
if user.private_key.is_some() {
    query_params.append_pair("orgUserHasExistingUser", "true");
}

initOrganization is never appended. orgUserHasExistingUser is appended only
when the invited user already has an account.

Web vault 2026.6.4 - /web-vault/app/main.*.js requires seven parameters:

fromUrlParams(e){ return null==e ? null :
  isGuid(e.organizationId) && isGuid(e.organizationUserId)
  && null!=e.email && null!=e.token && null!=e.organizationName
  && null!=e.initOrganization && null!=e.orgUserHasExistingUser
    ? new bi({...}) : null }

initOrganization is absent, so fromUrlParams returns null and the component
shows inviteAcceptFailed without calling the API.

This is a regression in 1.37.0. Web vault 2026.4.1 (shipped with 1.36.0) had
the same logic named fromParams and required only the two GUIDs, reading the
rest null-safely:

fromParams(e){ return null==e ? null :
  isGuid(e.organizationId) && isGuid(e.organizationUserId)
    ? Object.assign(new eh,{ email:e.email,
        initOrganization:"true"===(e.initOrganization?.toLowerCase()), ... })
    : null }

So: inviting a user who already has an account misses initOrganization;
inviting a brand new user misses both initOrganization and
orgUserHasExistingUser. Every invitation e-mail in 1.37.0 produces a dead
link.

Logs

LOG_LEVEL=debug, one full attempt to open an invitation link:

[request][INFO] GET /
[response][INFO] (web_index) GET / => 200 OK
[request][INFO] GET /app/main.<hash>.js
... static assets only ...
[request][INFO] GET /api/config
[response][INFO] (config) GET /api/config => 200 OK

No POST .../users/<member_id>/accept, no errors, no warnings.

Screenshots or Videos

No response

Additional Context

Workaround - append the missing parameter to the URL from the e-mail:

&initOrganization=false

For an invited user who has no account yet, also append:

&orgUserHasExistingUser=false

In practice: click the button in the e-mail, get the error, then append the
parameter in the browser address bar (where the URL is already decoded) and
press Enter. The invite is then accepted normally.

Suggested fix in src/mail.rs::send_invite - always send both:

query_params.append_pair("initOrganization", "false");
query_params.append_pair(
    "orgUserHasExistingUser",
    if user.private_key.is_some() { "true" } else { "false" },
);

Not the same as #7401 / #7355: there the link arrived truncated by
quoted-printable e-mail encoding. Here the token arrives intact and the missing
parameter is one the server never generates.

Ruled out during diagnosis: token validity (nbf reached, exp 5 days out, sub
and member_id matching the database), browser session, revoke + re-invite
(reinvite returns 200 OK), and registration order. The reliable signature is
the absence of an accept request in the log.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions