bitwarden/server
Architecture
Bitwarden Server is a polyglot-persistence multi-service .NET application. Every client talks first to the Identity service to obtain an OAuth access token, then to the Api service for vault operations, while a handful of supporting services (Events, EventsProcessor, Notifications, Admin, Billing, Icons, plus the commercial Sso and Scim projects) handle telemetry, real-time push, internal operations, payments, and enterprise integrations.
High-level service map
graph LR
subgraph Clients
Web["Web Vault"]
BrowserExt["Browser Extension"]
Mobile["Mobile / Desktop"]
CLI["bw CLI"]
end
subgraph BitwardenServer
Identity["Identity\n(OAuth/OIDC)"]
Api["Api"]
Events["Events\n(write API)"]
EP["EventsProcessor\n(queue drain)"]
Notifications["Notifications\n(SignalR hub)"]
Admin["Admin\n(Razor Pages)"]
Billing["Billing\n(Stripe/PayPal\nwebhooks)"]
Icons["Icons\n(favicon proxy)"]
Sso["Sso\n(SAML/OIDC IdP\nbridge)"]
Scim["Scim\n(provisioning API)"]
end
subgraph Storage
SqlDb[("SQL Server\n/MySQL/Postgres")]
Blobs[("Azure Blob /\nLocal Files")]
Cache[("Redis /\nDistributedCache")]
Bus[("Service Bus /\nRabbitMQ /\nAzure Queue")]
end
Stripe["Stripe / PayPal /\nBraintree"] --> Billing
Web -->|access token| Identity
BrowserExt --> Identity
Mobile --> Identity
CLI --> Identity
Web -->|JWT| Api
BrowserExt --> Api
Mobile --> Api
CLI --> Api
Mobile -->|WebSocket| Notifications
Web --> Notifications
Api -->|publishes| Events
Events --> Bus
Bus --> EP
EP --> SqlDb
Api --> SqlDb
Api --> Blobs
Api --> Cache
Identity --> SqlDb
Notifications --> Bus
Sso --> Identity
Scim --> SqlDb
Admin --> SqlDbEvery box in BitwardenServer is a separate ASP.NET Core process with its own Startup.cs, Dockerfile, appsettings.*.json, and entry-point script.
Service responsibilities
| Service | Role | Key entry point |
|---|---|---|
Identity |
OAuth 2.0 / OIDC token endpoint built on Duende IdentityServer. Handles login, password authentication, two-factor auth, device-trust, refresh, SSO callbacks, and the SCIM token issuer. | src/Identity/Startup.cs, src/Core/Auth/IdentityServer/ |
Api |
The main REST API for clients. Vault CRUD, organization management, sends, account settings, devices, billing self-service, secrets manager. | src/Api/Startup.cs |
Admin |
Razor-Pages admin UI for Bitwarden staff. Customer-support tools, billing operations, license generation, send/notification/log lookup. | src/Admin/Startup.cs |
Billing |
HTTP receiver for Stripe, PayPal IPN, BitPay, Braintree, and FreshDesk webhooks. Updates subscriptions and invoices in the database. | src/Billing/Startup.cs |
Events |
Tiny write API the clients hit to record user actions. Persists to a queue. | src/Events/Startup.cs |
EventsProcessor |
Background service that drains the event queue into the Event table (and Cosmos DB / Azure Table Storage in cloud). |
src/EventsProcessor/Program.cs |
Notifications |
SignalR hub clients connect to for real-time vault sync, login requests, and notification-center messages. | src/Notifications/NotificationsHub.cs, src/Notifications/HubHelpers.cs |
Icons |
Public favicon-proxy that fetches and caches website icons used by client autofill. | src/Icons/ |
Sso (commercial) |
SAML/OIDC bridge that lets enterprise users sign in to Bitwarden via their corporate IdP. Calls back into Identity. |
bitwarden_license/src/Sso/ |
Scim (commercial) |
SCIM 2.0 provisioning API for enterprise directory sync. | bitwarden_license/src/Scim/ |
Each service registers shared Bitwarden services through services.AddBaseServices(globalSettings) and services.AddDefaultServices(globalSettings) in src/Core/Utilities/ServiceCollectionExtensions.cs, then layers in service-specific bindings (e.g. services.AddCustomIdentityServices in the Identity host, services.AddBillingOperations in the API).
Request lifecycle (typical authenticated API call)
sequenceDiagram
participant C as Client
participant I as Identity
participant A as Api
participant DB as SQL Server
participant B as Service Bus
participant E as EventsProcessor
C->>I: POST /connect/token (password grant + 2FA)
I->>DB: validate user, master-password hash
I-->>C: access_token + refresh_token (JWT)
C->>A: GET /sync (Bearer JWT)
A->>DB: read User + Ciphers + Folders + Sends...
A-->>C: SyncResponseModel
C->>A: PUT /ciphers/{id} (modified item)
A->>DB: UPDATE Cipher
A->>B: enqueue CipherUpdated event
B->>E: deliver event
E->>DB: INSERT Event row
A->>Notifications: push CipherUpdate to user devicesData layer
The repository is unusual in supporting four databases for self-hosters and one (SQL Server) for the cloud. The shape is identical, but the two implementations live side-by-side:
- SQL Server (canonical, Dapper) —
src/Sql/dbo/is a SQL Server Database Project (.sqlproj) with every table, view, function, and stored procedure. Every repository undersrc/Infrastructure.Dapper/Repositories/calls those stored procedures via Dapper. SQL change scripts ship inutil/Migrator/DbScripts/and are applied byMsSqlMigratorUtility. - MySQL / Postgres / SQLite (Entity Framework) —
src/Infrastructure.EntityFramework/definesDatabaseContext, mappers, and EFIRepositoryimplementations. Migrations live inutil/MySqlMigrations/,util/PostgresMigrations/, andutil/SqliteMigrations/. The provider is selected at startup byglobalSettings.DatabaseProvider.
Every repository is registered against an interface (e.g. ICipherRepository); services.AddDatabaseRepositories(globalSettings) (src/SharedWeb/Utilities/ServiceCollectionExtensions.cs) picks the right concrete based on the configured provider. Application code never touches Dapper or EF directly — see systems/data-infrastructure.
Shared cross-service plumbing
| Concern | Lives in | Notes |
|---|---|---|
| Configuration | src/Core/Settings/GlobalSettings.cs |
Strongly-typed root-level settings bound from appsettings.*.json, env vars, and Azure Key Vault. |
| Auth/JWT | src/Core/Auth/IdentityServer/, src/SharedWeb/Utilities/ServiceCollectionExtensions.cs (AddIdentityAuthenticationServices) |
All services use the same Bearer scheme pointing at the Identity host. |
| Push | src/Core/Platform/Push/, src/Core/Platform/PushRegistration/ |
Multi-provider: Azure Notification Hub, SignalR, relay; selects via settings. |
| Event publishing | src/Core/Services/Implementations/EventService.cs plus Service Bus / RabbitMQ / Azure Queue clients |
The EventService writes either directly or onto a queue depending on host. |
src/Core/Platform/Mail/HandlebarsMailService.cs plus src/Core/MailTemplates/ |
All transactional email rendered server-side from MJML/Handlebars templates. | |
| Caching | services.AddDistributedCache(globalSettings) (src/SharedWeb/Utilities/DistributedCacheServiceCollectionExtensions.cs) |
Redis in cloud, in-memory in self-host by default. |
| Health | src/SharedWeb/Health/ |
/healthz and /healthz/extended endpoints on every cloud-hosted service. |
| Rate limiting | src/Core/Utilities/CustomIpRateLimitMiddleware.cs plus IpRateLimitOptions/IpRateLimitPolicies from appsettings.json |
AspNetCoreRateLimit library, disabled in self-host. |
Authentication flows
- Master-password login —
Identityaccepts the password grant, callsIUserService.CheckPasswordAsync, issues access + refresh tokens, optionally enforces 2FA viaTwoFactorAuthenticationValidator. - Two-factor — TOTP, Email, Duo, YubiKey, WebAuthn, Remember tokens; providers live in
src/Core/Auth/Identity/TokenProviders/. - WebAuthn passwordless / Login with device —
WebAuthnLoginGrantValidator+ theAuth/UserFeatures/WebAuthnLogin/commands. - SSO — corporate SAML/OIDC IdP →
bitwarden_license/Sso→Identity'sssoextension grant. Org-controlled per-user policies enforce SSO usage. - Trusted-device encryption (TDE) — admin-approval / device-key flow; see
src/Core/Auth/UserFeatures/DeviceTrust/. - API keys — organisations and personal users can mint client-credentials API keys; validated through
ApiClientextension grant. - SCIM bearer tokens — issued by the cloud control plane and validated in
bitwarden_license/Scim.
Background work and integrations
- Quartz.NET jobs — registered by
JobsHostedServicein each app (src/Api/Jobs/,src/Admin/Jobs/,src/Billing/Jobs/,src/Notifications/Jobs/,bitwarden_license/src/Sso/Jobs). Cleanup of expired devices, send tokens, sponsorships, and so on. - Hosted services —
ApplicationCacheHostedService(Service Bus topic that invalidatesIApplicationCacheService),AzureQueueHostedService(Notifications),HeartbeatHostedService(SignalR keep-alive),EventRepositoryHandler(EventsProcessor). - Event integrations —
src/Core/AdminConsole/Services/Implementations/EventIntegrations/plus per-org Slack/Teams/HEC/webhook integrations. - Push —
src/Core/Platform/Push/abstracts Azure Notification Hub, SignalR notifications, and relay-mode push (the relay is what self-hosted instances use to forward push to Bitwarden's cloud Notification Hub).
Cloud vs. self-host
The same codebase ships in both modes. Self-host differences are conditional on globalSettings.SelfHosted:
- IP rate limiting is disabled in self-host (
Startup.Configure). - Health-check endpoints are not exposed in self-host.
- Stripe / Braintree / PayPal / BitPay are skipped; subscriptions are handled by the licensed-organization flow.
- Push uses the relay (Bitwarden's cloud notification hub) by default.
- The
Setuputility inutil/Setup/is the install-time bootstrapper that generates an installation ID/key and the on-diskglobal.override.env.
See deployment for the full picture.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.