How Vaultwarden Implements the Bitwarden Client API: Supported Endpoints and Architecture
Vaultwarden implements the Bitwarden client API using the Rocket web framework in Rust, exposing REST endpoints under src/api that handle sync, ciphers, folders, and identity services while maintaining full compatibility with official Bitwarden clients.
Vaultwarden is a self-hosted, Rust-based implementation of the Bitwarden server API that allows users to run their own password management backend. Understanding how vaultwarden implements the Bitwarden client API reveals a lightweight yet comprehensive architecture that mirrors the official server behavior. This article examines the supported endpoints, request flow, and key source files in the dani-garcia/vaultwarden repository.
Architectural Overview
Vaultwarden uses the Rocket web framework to expose HTTP routes that correspond directly to Bitwarden client-side REST endpoints. The architecture follows a modular design where route definitions, business logic, and data models are cleanly separated.
Web Server and Route Registration
In src/main.rs, the application launches the Rocket server and mounts all API routes returned by api::routes(). The top-level src/api/mod.rs aggregates route objects from sub-modules and returns them to Rocket for registration.
// src/api/mod.rs - Route aggregation pattern
pub fn routes() -> Vec<Route> {
let mut routes = Vec::new();
routes.append(&mut core::routes());
routes.append(&mut identity::routes());
// ... additional modules
routes
}
Each endpoint is defined using Rocket attribute macros (#[get], #[post], #[put], #[delete]) in sub-modules under src/api/core/. The src/api/core/mod.rs file collects routes from ciphers, folders, organizations, and other domains into a unified vector.
Authentication and Headers
The auth::Headers struct in src/auth.rs extracts the Authorization: Bearer <token> header and validates the user session before any business logic executes. This provides handlers with an authenticated User object and request metadata including host, device type, and IP address.
// Handlers receive pre-validated authentication context
#[get("/ciphers/<id>")]
fn get_cipher(id: CipherId, headers: Headers) -> JsonResult {
// headers.user is already authenticated
}
Supported API Endpoints
Vaultwarden mirrors the full Bitwarden API surface, implementing endpoints across several functional categories. All routes return JSON responses structured exactly as official Bitwarden clients expect.
Sync and Data Retrieval
The sync endpoint aggregates all user data into a single response. Located in src/api/core/ciphers.rs, the sync function (lines 16-20) collects the user profile, folders, collections, ciphers, sends, policies, and domains.
- Method:
GET - Route:
/api/sync - Handler:
sync - Source:
src/api/core/ciphers.rs
Cipher Management
Ciphers (encrypted password entries) support full CRUD operations plus sharing and attachments. The src/api/core/ciphers.rs file contains the primary implementation with handlers including:
get_ciphers(lines 200-207): Lists all accessible ciphers viaGET /cipherspost_ciphers(lines 52-57): Creates new ciphers viaPOST /ciphersput_cipher(lines 68-73): Updates existing ciphers viaPUT /ciphers/<id>post_cipher_share(lines 334-339): Shares ciphers with collections viaPOST /ciphers/<id>/sharedelete_cipher(lines 76-84): Removes ciphers viaDELETE /ciphers/<id>
Attachment handling uses a two-step v2 API: post_attachment_v2 creates the metadata record, while post_attachment_v2_data receives the actual file upload.
Folders, Collections, and Organizations
Folder management resides in src/api/core/folders.rs with endpoints for listing (get_folders) and creating (post_folders). Organization and collection logic appears in src/api/core/organizations.rs, including:
get_collections(lines 853-860): Retrieves organization collectionspost_collections_update: Updates cipher collection memberships
The "Send" feature (secure file sharing) is implemented in src/api/core/sends.rs with get_sends and post_sends handlers.
Identity and Authentication
The OAuth-style token endpoint lives in src/api/identity.rs. The post_token handler processes POST /connect/token requests, handling password grants, refresh tokens, and device authorization.
Real-Time Notifications
After data mutations, handlers call Notify::send_* methods to push updates via WebSockets. The ws_hub handler in src/api/notifications.rs manages the GET /notifications/hub WebSocket connection for live client synchronization.
Request Lifecycle
Understanding how vaultwarden implements the Bitwarden client API requires examining the request flow:
- Route Matching: Rocket matches the URL to an attribute macro like
#[get("/ciphers/<cipher_id>")] - Parameter Parsing: Path and query parameters convert to typed arguments (e.g.,
cipher_id: CipherId) - Authentication: The
Headersguard extracts and validates the bearer token, supplying theUserobject - Authorization: Business logic checks permissions using model methods like
cipher.is_write_accessible_to_user - Response Building: Handlers use
serde_json::json!and modelto_jsonmethods to format responses - Push Notification: After mutations,
Notifytriggers WebSocket updates through the notifications service
Practical API Examples
Sync All Client Data
curl -s -H "Authorization: Bearer $TOKEN" \
-H "User-Agent: Bitwarden/2025.12.0" \
"$BASE_URL/api/sync"
This calls the sync function in src/api/core/ciphers.rs, returning a JSON object with "object":"sync" containing all user vault data.
Create a New Login Cipher
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type":1,
"name":"My Site",
"login":{"username":"alice","password":"s3cr3t"},
"folderId":null
}' \
"$BASE_URL/api/ciphers"
The post_ciphers handler parses CipherData, invokes Cipher::new, and delegates to update_cipher_from_data for validation and persistence.
Upload an Attachment (v2 API)
Step 1: Request upload URL via post_attachment_v2:
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"<encrypted-key>","file_name":"secret.pdf","file_size":12345}' \
"$BASE_URL/api/ciphers/<cipher_id>/attachment/v2"
Step 2: Upload file data via post_attachment_v2_data:
curl -X POST -F "[email protected]" \
"$BASE_URL/api/ciphers/<cipher_id>/attachment/<attachment_id>"
Share a Cipher with Collections
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ciphers":[{"id":"<cipher-id>"}],"collectionIds":["<collection-id>"]}' \
"$BASE_URL/api/ciphers/share"
This invokes put_cipher_share_selected, which iterates through ciphers and calls share_cipher_by_uuid to update the CollectionCipher join table after validating permissions.
Summary
- Vaultwarden uses the Rocket framework to register REST routes in
src/api/mod.rsandsrc/api/core/mod.rs, mounting them insrc/main.rs. - Core endpoints cover sync (
/api/sync), cipher CRUD (/api/ciphers/*), folders (/api/folders), organizations (/api/organizations), and sends (/api/sends). - Authentication occurs through the
auth::Headersguard insrc/auth.rs, which validates bearer tokens before handlers execute. - Real-time updates flow through the WebSocket hub in
src/api/notifications.rs, triggered byNotifycalls after data mutations. - File attachments use a two-step v2 API process defined in
src/api/core/ciphers.rsfor metadata creation and binary upload.
Frequently Asked Questions
How does Vaultwarden handle authentication for API requests?
Vaultwarden validates bearer tokens through the auth::Headers struct defined in src/auth.rs. This guard extracts the Authorization header, validates the JWT token against the database, and injects the authenticated User object directly into route handlers. The system supports standard Bitwarden authentication flows including password grants and refresh tokens via the post_token handler in src/api/identity.rs.
Which Bitwarden client features are not supported by Vaultwarden?
While Vaultwarden implements the vast majority of client-facing endpoints including sync, ciphers, folders, collections, sends, emergency access, and attachments, certain enterprise features may differ from the official cloud implementation. The repository tracks upstream Bitwarden versions (currently 2025.12.0) and implements features selectively based on self-hosted use cases. Specific enterprise policies and advanced administrative features may have limited support compared to the official Bitwarden server.
How does Vaultwarden push real-time updates to connected clients?
After any data mutation (creating, updating, or deleting ciphers), handlers invoke methods on the Notify struct to broadcast changes. The ws_hub handler in src/api/notifications.rs manages WebSocket connections at GET /notifications/hub, maintaining persistent connections to clients and pushing JSON payloads that trigger client-side vault refreshes without requiring manual sync requests.
Where is the cipher sharing logic implemented in the source code?
Cipher sharing functionality resides in src/api/core/ciphers.rs. The put_cipher_share_selected handler processes POST /api/ciphers/share requests, while share_cipher_by_uuid contains the core logic for validating collection permissions and updating the CollectionCipher join table. These functions ensure users can only share ciphers with collections where they have appropriate write access.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →