Open-Source Wikis

/

Bitwarden Server

/

Apps

/

Identity

bitwarden/server

Identity

Active contributors: auth team.

Purpose

src/Identity/ is the OAuth 2.0 / OpenID Connect token endpoint for Bitwarden. Every client (web vault, browser ext, mobile, desktop, CLI, directory connector) authenticates here first to obtain an access + refresh token; the resulting JWT is then accepted by every other service. The Identity host is built on Duende IdentityServer with Bitwarden-authored extension grants, custom token providers, and ASP.NET Core Identity for the user store.

Directory layout

src/Identity/
├── Program.cs / Startup.cs
├── Controllers/
│   ├── AccountsController.cs           # Pre-token helpers (prelogin, register-finalize, register-anonymous)
│   ├── SsoController.cs                # /sso/PreValidate, /sso/ExternalChallenge
│   └── ...
├── IdentityServer/                     # Identity-host-specific IdentityServer config (the meaty part lives in src/Core/Auth/IdentityServer)
├── Models/                             # Request/response models for the controllers
├── Utilities/                          # Identity-specific extensions (e.g. ServiceCollectionExtensions for AddCustomIdentityServerServices)
├── Views/                              # SSO callback / error views (Razor)
├── appsettings.*.json
└── Dockerfile / build.sh / entrypoint.sh

The bulk of the IdentityServer customisation lives in the shared library src/Core/Auth/IdentityServer/:

src/Core/Auth/IdentityServer/
├── ServiceCollectionExtensions.cs    # AddCustomIdentityServerServices
├── ProfileService.cs                 # Builds the access-token claims for a user
├── ApiClient.cs                      # Server-to-server / org / installation / SCIM clients
├── DynamicClientStore.cs             # Org-mounted clients (e.g. SSO callback)
├── StaticClientStore.cs              # The fixed Bitwarden first-party clients
├── ApiResources.cs                   # The "api", "api.organization", "api.installation", etc. resources
├── AuthorizationCodeStore.cs         # Persisted-grant store backed by IDistributedCache
├── PersistedGrantStore.cs            # Same but for refresh tokens / device codes
├── DynamicClientStore.cs             # Pulls per-org clients from the DB
├── ClientProviders/                  # Resolves clients by organisation, installation, or SCIM token
├── RequestValidators/                # Custom resource-owner / extension grant validators
│   ├── ResourceOwnerPasswordValidator.cs
│   ├── WebAuthnLoginGrantValidator.cs
│   ├── SsoExtensionGrantValidator.cs
│   ├── AuthorizationCodeGrantValidator.cs
│   └── ...
├── UserDecryptionOptionsBuilder.cs   # Computes the `userDecryptionOptions` payload returned with the token
└── VaultCorsPolicyService.cs

ASP.NET Core Identity glue lives in src/Core/Auth/Identity/:

  • UserStore.cs — bridges IUserRepository to ASP.NET Core Identity.
  • RoleStore.cs — minimal role store (Bitwarden uses claims, not roles, but the abstraction is required).
  • Policies.csPolicies.Application, Policies.Web, Policies.Push, ... — shared with the API.
  • TokenProviders/ — every two-factor provider (TOTP, Email, Duo, YubiKey, WebAuthn, Remember).

Key abstractions

Type Purpose
Startup (src/Identity/Startup.cs) Registers data protection, distributed cache, IdentityServer, ASP.NET Identity, Bitwarden services, the sso external OIDC handler.
AddCustomIdentityServerServices (src/Core/Auth/IdentityServer/ServiceCollectionExtensions.cs) Adds IdentityServer with Bitwarden's grant types, persisted-grant store, signing credentials, and dynamic client store.
ResourceOwnerPasswordValidator Master-password grant: validates email + master-password hash via IUserService.CheckPasswordAsync, then defers to 2FA.
BaseRequestValidator (in RequestValidators/) Centralised post-credential-check logic: device tracking, 2FA enforcement, captcha gating, security stamp checks, login policy enforcement.
WebAuthnLoginGrantValidator Login With Passkey extension grant; uses the passkey PRF blob to decrypt the user key.
SsoExtensionGrantValidator Validates a one-shot sso token issued by Sso and exchanges it for an access token.
AuthorizationCodeGrantValidator Standard OIDC code-flow validator.
ProfileService Decides which claims land in the access token (user id, email, name, premium, security stamp, organization claims, etc.).
UserDecryptionOptionsBuilder Adds userDecryptionOptions to the token response so clients know how to derive the user key (master-password, device-trust, key-connector, …).
Policies.cs (src/Core/Auth/Identity/Policies.cs) The set of authorization policies used across all services.

How it works

sequenceDiagram
    participant C as Client
    participant Id as Identity
    participant DB
    participant TFA as 2FA Provider

    C->>Id: POST /connect/token (grant_type=password,<br/>email, masterPasswordHash, captchaResponse?)
    Id->>DB: ResourceOwnerPasswordValidator → IUserService.CheckPasswordAsync
    Id->>Id: BaseRequestValidator: device trust, captcha, login policy
    alt 2FA required
        Id-->>C: 400 invalid_grant + TwoFactorProviders
        C->>TFA: complete TOTP/Email/Duo/WebAuthn
        C->>Id: POST /connect/token (..., twoFactorToken, twoFactorProvider)
        Id->>Id: TwoFactorAuthenticationValidator
    end
    Id->>Id: ProfileService → claims
    Id->>Id: UserDecryptionOptionsBuilder
    Id-->>C: access_token + refresh_token (JWT) + userDecryptionOptions

Other grant types follow the same shape but plug in different validators:

  • webauthn: passwordless via FIDO2 PRF.
  • auth_request: login-with-device (a logged-in device approves).
  • sso: one-shot SSO bridge (used by bitwarden_license/Sso).
  • client_credentials: org / installation API keys.
  • refresh_token: rotates the refresh token on each use.

Two-factor providers

Implementations live in src/Core/Auth/Identity/TokenProviders/:

  • AuthenticatorTokenProvider — TOTP (Microsoft Authenticator, Authy, Google Authenticator).
  • EmailTokenProvider — six-digit code via mail.
  • DuoTokenProvider / OrganizationDuoTokenProvider — Duo Security (personal + org-issued).
  • WebAuthnTokenProvider — FIDO2 second factor.
  • YubicoOtpTokenProvider — YubiKey OTP.
  • RememberTokenProvider — "remember this device for 30 days" cookie.

TwoFactorAuthenticationValidator (src/Core/Auth/IdentityServer/RequestValidators/TwoFactorAuthenticationValidator.cs) decides which provider is required given the user's enrolment + organization policy.

SSO bridge

The Identity host registers an external OpenID Connect handler called sso:

.AddOpenIdConnect("sso", "Single Sign On", options =>
{
    options.Authority = globalSettings.BaseServiceUri.InternalSso;
    options.ClientId = "oidc-identity";
    options.ClientSecret = globalSettings.OidcIdentityClientKey;
    ...
});

bitwarden_license/Sso is both an OIDC IdP (this handler talks to it) and a SAML / OIDC SP (it talks to the customer's IdP). The SsoExtensionGrantValidator consumes a one-shot token to convert that flow into a Bitwarden access token. See features/sso-saml.

Persisted grants and tokens

IdentityServer's persisted-grant store is backed by IDistributedCache (Redis in cloud, in-memory in self-host) via PersistedGrantStore and AuthorizationCodeStore. Refresh-token rotation is enabled by default; the SecurityStamp on the user invalidates all outstanding tokens when bumped.

Cookie-based grants for the SSO redirect flow use a custom DistributedCacheTicketStore (src/Core/Auth/Identity/DistributedCacheTicketStore.cs) so cookies stay small.

Self-host quirks

  • Startup.Configure adds app.UsePathBase("/identity") when globalSettings.SelfHosted is true; the bundled nginx config routes /identity/* to this app.
  • Rate limiting is disabled in self-host.
  • The dev cert path differs (src/Identity/identity_server_dev.pfx is generated by dev/create_certificates_*.sh).

Entry points for modification

  • Adding a new grant type → add an IExtensionGrantValidator in src/Core/Auth/IdentityServer/RequestValidators/, register it in AddCustomIdentityServerServices.
  • Adding a new 2FA provider → implement IUserTwoFactorTokenProvider<User> in src/Core/Auth/Identity/TokenProviders/, add an enum value to TwoFactorProviderType, surface in TwoFactorAuthenticationValidator.
  • Changing what claims appear in the JWT → edit ProfileService.cs and the UserDecryptionOptionsBuilder.
  • Adding a new client (e.g. for a new partner integration) → add it to StaticClientStore or mint org-bound API keys via the AdminConsole. See features/auth.

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

Identity – Bitwarden Server wiki | Factory