# Compatibility Considerations When Using Official Bitwarden Clients with Vaultwarden

> Discover Vaultwarden client compatibility. Learn how official Bitwarden clients interact with Vaultwarden and which features are supported based on client version.

- Repository: [Daniel García/vaultwarden](https://github.com/dani-garcia/vaultwarden)
- Tags: compatibility-considerations
- Published: 2026-03-07

---

**Vaultwarden parses the `Bitwarden-Client-Version` header from every request to gate features, ensuring older official clients receive filtered API responses while newer clients access advanced capabilities like SSH key support.**

Vaultwarden implements the Bitwarden Client API as a drop-in replacement for the official service, maintaining seamless compatibility through version detection and adaptive response filtering. Understanding these compatibility considerations when using official Bitwarden clients with Vaultwarden helps administrators troubleshoot client behavior and predict feature availability across different client versions.

## Client Version Detection

Vaultwarden extracts the client version from every incoming request to determine which features the client can safely handle. In [`src/auth.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/auth.rs), the server implements a `FromRequest` guard that parses the `Bitwarden-Client-Version` header into a `ClientVersion` struct using semantic versioning:

```rust
// src/auth.rs
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ClientVersion {
    type Error = &'static str;

    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        let headers = request.headers();

        // The official Bitwarden apps always send this header.
        let Some(version) = headers.get_one("Bitwarden-Client-Version") else {
            err_handler!("No Bitwarden-Client-Version header provided")
        };

        // Validate it follows semver.
        let Ok(version) = semver::Version::parse(version) else {
            err_handler!("Invalid Bitwarden-Client-Version header provided")
        };

        Outcome::Success(ClientVersion(version))
    }
}

```

The extracted `ClientVersion` is passed as an optional parameter to route handlers throughout the codebase, including `sync`, `identity`, and cipher-related endpoints. This allows Vaultwarden to adjust its behavior dynamically based on the client's reported version.

## Version-Gated Feature Support

To prevent JSON parsing errors on older clients, Vaultwarden hides features that exceed a client's understood schema. The most prominent example occurs in the `/sync` endpoint within [`src/api/core/ciphers.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/core/ciphers.rs), where SSH keys are filtered out for clients older than version 2024.12.0:

```rust
// src/api/core/ciphers.rs
#[get("/sync?<data..>")]
async fn sync(
    data: SyncData,
    headers: Headers,
    client_version: Option<ClientVersion>,
    conn: DbConn,
) -> JsonResult {
    // ...

    // Filter out SSH keys if the client version is less than 2024.12.0
    let show_ssh_keys = if let Some(client_version) = client_version {
        let ver_match = semver::VersionReq::parse(">=2024.12.0").unwrap();
        ver_match.matches(&client_version.0)
    } else {
        false
    };
    if !show_ssh_keys {
        ciphers.retain(|c| c.atype != 5); // 5 = SSH key type
    }

    // ...
}

```

Clients reporting versions prior to 2024.12.0 receive sync responses that omit all cipher objects where `"type": 5`, effectively hiding SSH key support without breaking the client's vault decryption or sync process.

## Experimental Client Feature Flags

Administrators can toggle experimental features via the `EXPERIMENTAL_CLIENT_FEATURE_FLAGS` environment variable. In [`src/util.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/util.rs), the `parse_experimental_client_feature_flags` function processes these flags while filtering out deprecated values to maintain backward compatibility with legacy installations:

```rust
// src/util.rs
/// Parses the experimental client feature flags string into a HashMap.
pub fn parse_experimental_client_feature_flags(
    experimental_client_feature_flags: &str,
) -> HashMap<String, bool> {
    // Deprecated flags are filtered out to keep old installations from breaking.
    const DEPRECATED_FLAGS: &[&str] = &[
        "autofill-overlay",
        "autofill-v2",
        "browser-fileless-import",
        "extension-refresh",
        "fido2-vault-credentials",
    ];
    experimental_client_feature_flags
        .split(',')
        .filter_map(|f| {
            let flag = f.trim();
            if !flag.is_empty() && !DEPRECATED_FLAGS.contains(&flag) {
                return Some((flag.to_owned(), true));
            }
            None
        })
        .collect()
}

```

The resulting flag map is consulted in [`src/api/core/mod.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/core/mod.rs) and other locations to conditionally enable behavior without exposing unstable features to incompatible clients.

## Legacy Protocol Support

Beyond version gating, Vaultwarden maintains compatibility through protocol-specific adaptations:

**U2F Legacy Support**: In [`src/api/core/two_factor/webauthn.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/core/two_factor/webauthn.rs), the server adds an `appid` field only when necessary to support legacy U2F hardware keys, ensuring older authenticators continue to function with modern WebAuthn flows.

**Identity Flow Adaptation**: The [`src/api/identity.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/identity.rs) handlers propagate `client_version` through login and two-factor authentication processes, influencing SSO redirect behavior and two-factor method availability based on the client's capabilities.

**Icon Download Compatibility**: Special handling in [`src/util.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/util.rs) addresses edge cases where specific clients, such as the Bitwarden Desktop application, fail to download icons under certain conditions, preventing 404 errors that would otherwise disrupt the user experience.

## Graceful Degradation Strategy

When Vaultwarden encounters a feature request from an incompatible client, it employs **field omission** rather than error emission. The server simply excludes unsupported fields from JSON payloads, maintaining the seamless experience expected from the official Bitwarden service. No error codes are returned for version mismatches.

For truly unsupported API routes or malformed requests, Vaultwarden returns identical HTTP status codes (`404`, `400`, `401`, etc.) to those returned by the official Bitwarden servers, ensuring client-side error handling behaves identically whether connected to Vaultwarden or the official cloud service.

## Testing Client Compatibility

To verify version-specific behavior, you can simulate different client versions using the `Bitwarden-Client-Version` header:

```bash

# Request sync as Android client v2024.12.0 (receives SSH keys)

curl -X GET "https://my-vaultwarden-instance.com/api/sync" \
     -H "Authorization: Bearer <access_token>" \
     -H "Bitwarden-Client-Version: 2024.12.0"

# Request sync as older client v2024.10.0 (excludes SSH keys)

curl -X GET "https://my-vaultwarden-instance.com/api/sync" \
     -H "Authorization: Bearer <access_token>" \
     -H "Bitwarden-Client-Version: 2024.10.0"

```

To enable experimental features for testing:

```bash

# docker-compose.yml

services:
  vaultwarden:
    image: vaultwarden/server:latest
    environment:
      - EXPERIMENTAL_CLIENT_FEATURE_FLAGS=new-password-generator

```

## Summary

- **Version Extraction**: Vaultwarden reads the `Bitwarden-Client-Version` header in [`src/auth.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/auth.rs) to determine client capabilities using semantic versioning.
- **Feature Gating**: Advanced features like SSH keys (type 5) are filtered from responses when `client_version` reports versions older than 2024.12.0.
- **Flag Management**: The `EXPERIMENTAL_CLIENT_FEATURE_FLAGS` environment variable controls beta features, with deprecated flags automatically filtered in [`src/util.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/util.rs).
- **Silent Compatibility**: Unsupported features are omitted from JSON responses rather than returning errors, preserving the official Bitwarden client experience.
- **Protocol Adaptation**: Legacy U2F `appid` fields and icon download workarounds ensure older hardware and specific clients function correctly.

## Frequently Asked Questions

### How does Vaultwarden handle outdated Bitwarden clients?

Vaultwarden inspects the `Bitwarden-Client-Version` header and filters response payloads to exclude features the client cannot parse. For example, clients older than version 2024.12.0 receive sync data with SSH keys removed, preventing JSON deserialization errors while allowing the vault to function normally.

### Can I force-enable features for older clients?

No. While you can set `EXPERIMENTAL_CLIENT_FEATURE_FLAGS` to enable beta functionality, Vaultwarden's core compatibility logic—such as the SSH key filtering in [`src/api/core/ciphers.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/core/ciphers.rs)—uses hardcoded version requirements to prevent breaking older clients. Feature flags are intended for testing new Bitwarden features, not bypassing version checks.

### What happens if the `Bitwarden-Client-Version` header is missing?

The `ClientVersion` extractor in [`src/auth.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/auth.rs) returns an error outcome if the header is absent or contains an invalid semver string. However, all official Bitwarden clients (desktop, mobile, browser extensions, and CLI) reliably send this header, so missing headers typically indicate non-standard or automated API requests rather than legitimate client connections.

### Are there compatibility differences between Bitwarden Desktop and mobile clients?

Yes. Specific edge cases exist for different client types. For instance, [`src/util.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/util.rs) contains special handling for Bitwarden Desktop icon downloads, and the WebAuthn implementation in [`src/api/core/two_factor/webauthn.rs`](https://github.com/dani-garcia/vaultwarden/blob/main/src/api/core/two_factor/webauthn.rs) adds legacy U2F `appid` fields for clients that require them. These adaptations ensure consistent functionality across the diverse Bitwarden client ecosystem.