Open-Source Wikis

/

Bitwarden Server

/

Systems

/

Push & SignalR

bitwarden/server

Push & SignalR

Active contributors: platform team.

Purpose

Bitwarden clients are kept in sync with the server via push notifications. The server notifies a user's connected devices when their vault changes (cipher created/updated/deleted, folder change, organization update, login request). The push pipeline is multi-provider:

  • SignalR — the Notifications host fans out push messages to currently-connected clients (web vault, browser extension, desktop, CLI).
  • Azure Notification Hub — the API talks directly to ANH for mobile (iOS APNs, Android FCM/HMS) push.
  • Relay mode — self-hosted instances forward push to Bitwarden's cloud Notification Hub via the relay so customer mobile apps still receive native notifications.

Directory layout

src/Core/Platform/Push/
├── IPushNotificationService.cs            # Domain-facing interface
├── PushType.cs                            # Every push event the server can emit
├── NotificationsApiPushNotificationService.cs    # Calls the Notifications host (SignalR)
├── NotificationHubPushNotificationService.cs     # Calls Azure Notification Hub (mobile)
├── RelayPushNotificationService.cs               # Self-host: forwards to upstream cloud relay
├── MultiServicePushNotificationService.cs        # Composite that calls multiple providers
├── PushTokenService.cs                           # Manages installation + device push tokens
└── ...

src/Core/Platform/PushRegistration/
├── IPushRegistrationService.cs            # Register/unregister device tokens
├── NotificationHubPushRegistrationService.cs
└── ...

src/Notifications/
├── NotificationsHub.cs / AnonymousNotificationsHub.cs / HubHelpers.cs
└── (see apps/notifications.md)

Key abstractions

Type Path Description
IPushNotificationService src/Core/Platform/Push/IPushNotificationService.cs Emit-side interface: PushSyncCipherUpdate, PushSyncFolderCreate, PushAuthRequestResponse, ...
PushType src/Core/Platform/Push/PushType.cs The enum of events; intentionally outside CODEOWNERS so any team can extend it.
IPushRegistrationService src/Core/Platform/PushRegistration/IPushRegistrationService.cs Register / unregister a device's push tokens (APNs / FCM tags).
MultiServicePushNotificationService src/Core/Platform/Push/MultiServicePushNotificationService.cs Composite that fans a single emit out to SignalR + ANH + Relay as needed.
RelayPushNotificationService src/Core/Platform/Push/RelayPushNotificationService.cs Self-host bridge: HTTPs POST to Bitwarden's cloud relay, signed with the installation key.
NotificationsHub src/Notifications/NotificationsHub.cs The SignalR endpoint clients connect to.
HubHelpers src/Notifications/HubHelpers.cs 13KB router that maps PushType → SignalR group sends.

How it works

graph LR
    Api["src/Core/<Domain>/...\n(IPushNotificationService.PushSyncCipherUpdate)"] --> Multi["MultiServicePushNotificationService"]
    Multi --> Sig["NotificationsApiPushNotificationService"]
    Multi --> ANH["NotificationHubPushNotificationService"]
    Multi --> Relay["RelayPushNotificationService\n(self-host only)"]
    Sig --> NoHost["Notifications host\n(SignalR /hub)"]
    ANH --> Cloud["Azure Notification Hub"]
    Relay --> Upstream["Bitwarden cloud relay"]
    NoHost --> WebClient["Web vault / Browser ext\n/ Desktop / CLI"]
    Cloud --> Mobile["iOS / Android apps"]
    Upstream --> Cloud

When the API updates a cipher, it calls IPushNotificationService.PushSyncCipherUpdate(cipher, collectionIds). The MultiServicePushNotificationService decides which downstream services to call based on globalSettings.Notifications and globalSettings.PushHub:

  • If a Notifications URL is configured → POST to it; the Notifications host enqueues into HubHelpers which calls Clients.Group(userId).SendAsync(...).
  • If globalSettings.PushHub.HubName is configured → call ANH with tags so iOS/Android receive a native push.
  • If globalSettings.Installation.Id indicates self-host → call the relay.

Push registration

Mobile devices register their APNs/FCM token via Api.DevicesController (src/Api/Controllers/DevicesController.cs). The IPushRegistrationService writes the registration to ANH (for cloud) or the local registration table.

When a user signs out or removes a device, the same registration is deleted to avoid stale push targets.

Why three providers?

  • SignalR is great for currently-open clients but doesn't reach mobile devices that are backgrounded.
  • ANH handles native push but requires Apple / Google credentials that customers can't reasonably manage themselves — hence the relay.
  • Relay mode lets self-hosted customers pay nothing extra for mobile push while keeping all their data on-prem.

Entry points for modification

  • New push event → add value to PushType, extend IPushNotificationService and every implementation, route in HubHelpers.
  • New push provider → implement IPushNotificationService, register through MultiServicePushNotificationService.
  • Change registration tags → edit NotificationHubPushRegistrationService.GetTagsForRegistration.

For the public connection contract, see apps/notifications.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Push & SignalR – Bitwarden Server wiki | Factory