Open-Source Wikis

/

Bitwarden Server

/

Systems

/

IdentityServer & auth pipeline

bitwarden/server

IdentityServer & auth pipeline

Active contributors: auth team.

Purpose

Bitwarden's authentication and OAuth/OIDC stack is built on Duende IdentityServer plus ASP.NET Core Identity, with a substantial layer of Bitwarden-authored extension grants, custom validators, and stores. The wiring is split between src/Identity/ (the host) and src/Core/Auth/IdentityServer/ (the reusable pieces that other services also need).

Directory layout

src/Core/Auth/IdentityServer/
├── ServiceCollectionExtensions.cs    # AddCustomIdentityServerServices: signing keys, stores, validators, profile service
├── ProfileService.cs                 # Builds the JWT claim set
├── UserDecryptionOptionsBuilder.cs   # Adds userDecryptionOptions to the token response
├── ApiResources.cs / ApiClient.cs / StaticClientStore.cs / DynamicClientStore.cs
├── PersistedGrantStore.cs            # Refresh tokens / device codes (IDistributedCache backed)
├── AuthorizationCodeStore.cs         # OIDC auth-code store
├── ClientProviders/                  # Resolve clients for installations / SCIM tokens / orgs
├── RequestValidators/                # 1 file per grant type (password, sso, webauthn, auth_request, refresh, ApiClient)
├── VaultCorsPolicyService.cs         # Per-CORS-origin policy for IdentityServer's discovery endpoints
└── Constants/

src/Core/Auth/Identity/
├── Policies.cs                       # Cross-service authz policy names
├── Claims.cs                         # JWT claim type constants
├── UserStore.cs / RoleStore.cs       # ASP.NET Core Identity stores backed by IUserRepository
├── CustomIdentityServiceCollectionExtensions.cs   # AddCustomIdentityServices
├── DistributedCache* / TokenRetrieval.cs           # OIDC cookie-store + bearer-token helpers
└── TokenProviders/                   # 2FA: TOTP, Email, Duo, WebAuthn, YubiKey, Remember

Key abstractions

Type Purpose
AddCustomIdentityServerServices(env, globalSettings) One-shot service registration for every service that needs IdentityServer (just Identity today).
BaseRequestValidator (in RequestValidators/) Shared post-credential validator: device tracking, 2FA enforcement, captcha gating, security-stamp checks, login policy enforcement. Inherited by every grant validator.
ResourceOwnerPasswordValidator Master-password grant: validates email + master-password hash via IUserService.CheckPasswordAsync.
WebAuthnLoginGrantValidator Login With Passkey extension grant; uses the passkey PRF blob.
SsoExtensionGrantValidator Validates the one-shot SsoTokenable issued by the Sso host.
AuthRequestExtensionGrantValidator Login-with-device flow: a logged-in device approves a pending auth request.
ProfileService Adds Bitwarden claims (user id, email, name, premium, security stamp, organization claims) to the access token.
UserDecryptionOptionsBuilder Computes userDecryptionOptions so clients know whether to derive the user key from the master password, a trusted device, key connector, or a combination.
Policies Application, Web, Push, Organization, Installation, Licensing, Secrets, Send — all the authz policy names used elsewhere.
Claims Constant claim-type strings used in policies and authorization handlers.

How it works

graph TD
    A[Client POST /connect/token] --> B[IdentityServer pipeline]
    B --> C{grant_type?}
    C -->|password| D[ResourceOwnerPasswordValidator]
    C -->|webauthn| E[WebAuthnLoginGrantValidator]
    C -->|auth_request| F[AuthRequestExtensionGrantValidator]
    C -->|sso| G[SsoExtensionGrantValidator]
    C -->|client_credentials| H[ApiClient validators]
    C -->|refresh_token| I[Persisted-grant store]
    D --> Z[BaseRequestValidator: 2FA + captcha + policies]
    E --> Z
    F --> Z
    G --> Z
    Z --> P[ProfileService → claims]
    P --> U[UserDecryptionOptionsBuilder]
    U --> R[Token response]

Persisted-grant storage

PersistedGrantStore and AuthorizationCodeStore use ASP.NET Core's IDistributedCache rather than the IdentityServer SQL store. In cloud this is Redis; in self-host it falls back to an in-memory cache. Refresh-token rotation is on by default (RefreshTokenUsage = OneTimeOnly).

Cookie-based auth (used during the SSO redirect flow) uses DistributedCacheTicketStore in src/Core/Auth/Identity/ so cookie payload size stays small.

ASP.NET Core Identity

UserStore.cs and RoleStore.cs adapt Bitwarden's User entity + IUserRepository to the ASP.NET Core Identity abstractions. LowerInvariantLookupNormalizer ensures emails are case-insensitive lookup keys.

Two-factor providers are registered via AddTokenProvider<T> calls in CustomIdentityServiceCollectionExtensions. Each implements IUserTwoFactorTokenProvider<User>. The TwoFactorAuthenticationValidator decides which provider is required given the user's enrolment plus organisation policy (RequireTwoFactorPolicy).

Authorization policies

Five JWT scopes are common: api, api.organization, api.installation, api.secrets, api.send.access, api.licensing, api.push. Plus the SSO and SCIM tokens use bespoke scopes. The matching policy definitions live in src/Api/Startup.cs (AddPolicy(Policies.X, ...)) and replicate across services via AddIdentityAuthenticationServices.

Integration points

  • Identity host — the only service that issues tokens.
  • All other servicesconsume tokens via AddIdentityAuthenticationServices (src/SharedWeb/Utilities/ServiceCollectionExtensions.cs), which configures JWT bearer auth pointing at the Identity host's discovery endpoint.
  • Sso host — issues SsoTokenables consumed by SsoExtensionGrantValidator.
  • Admin host — does not run IdentityServer; instead uses passwordless email-link auth and signs its own session cookies.

Entry points for modification

  • New grant type → IExtensionGrantValidator in src/Core/Auth/IdentityServer/RequestValidators/, register in AddCustomIdentityServerServices.
  • New 2FA provider → implement IUserTwoFactorTokenProvider<User> in src/Core/Auth/Identity/TokenProviders/, add TwoFactorProviderType enum value, surface in TwoFactorAuthenticationValidator.
  • Change JWT claims → edit ProfileService.
  • Tighten / loosen a policy → edit the AddPolicy(...) call in Api.Startup (and any other host that re-declares it).

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

IdentityServer & auth pipeline – Bitwarden Server wiki | Factory