Skip to main content
The Identity service provides authentication and authorization for Bitwarden Server using OAuth 2.0 and OpenID Connect protocols, built on Duende IdentityServer.

Overview

The Identity service handles:
  • User Authentication: Password-based login, SSO integration
  • OAuth 2.0 Flows: Authorization code, client credentials, resource owner password
  • OpenID Connect: Identity token issuance and validation
  • Token Management: Access tokens, refresh tokens, identity tokens
  • SSO Integration: External authentication via SSO service
  • Device Authorization: Device-specific authentication flows

Architecture

OAuth 2.0 Flows

Authorization Code Flow

Used by web and mobile clients for user authentication:
1

Authorization Request

Client redirects to /connect/authorize with client_id and redirect_uri
2

User Authentication

User authenticates with username/password or SSO
3

Authorization Code

Identity service redirects back with authorization code
4

Token Exchange

Client exchanges code for access token at /connect/token

Client Credentials Flow

Used for server-to-server authentication (Public API, SCIM):
curl -X POST "https://identity.bitwarden.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=organization.{guid}" \
  -d "client_secret={secret}" \
  -d "scope=api.organization"

Resource Owner Password Flow

Used by CLI and desktop clients:
curl -X POST "https://identity.bitwarden.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "username={email}" \
  -d "password={password}" \
  -d "scope=api offline_access" \
  -d "client_id=cli" \
  -d "deviceType=8" \
  -d "deviceIdentifier={device_id}" \
  -d "deviceName={device_name}"

Configuration

Application Settings

From src/Identity/Startup.cs:33:
Service Configuration
public void ConfigureServices(IServiceCollection services)
{
    // Settings
    var globalSettings = services.AddGlobalSettingsServices(Configuration, Environment);
    
    // Data Protection
    services.AddCustomDataProtectionServices(Environment, globalSettings);
    
    // Repositories
    services.AddDatabaseRepositories(globalSettings);
    
    // Caching
    services.AddMemoryCache();
    services.AddDistributedCache(globalSettings);
    
    // Disable claim mapping
    JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
    
    // Authentication
    services.AddDistributedIdentityServices()
        .AddAuthentication()
        .AddCookie(AuthenticationSchemes.BitwardenExternalCookieAuthenticationScheme)
        .AddOpenIdConnect("sso", "Single Sign On", options =>
        {
            options.Authority = globalSettings.BaseServiceUri.InternalSso;
            options.ClientId = "oidc-identity";
            options.ClientSecret = globalSettings.OidcIdentityClientKey;
            options.ResponseType = "code";
            options.SaveTokens = false;
            options.GetClaimsFromUserInfoEndpoint = true;
        });
    
    // IdentityServer
    services.AddCustomIdentityServerServices(Environment, globalSettings);
    
    // Identity
    services.AddCustomIdentityServices(globalSettings);
}

IdentityServer Configuration

The service uses Duende IdentityServer for OAuth/OIDC implementation:
IdentityServer is configured with signing certificates for token validation.
Certificate Configuration
{
  "globalSettings": {
    "identityServer": {
      "certificateThumbprint": "ABC123..."
    }
  }
}

Supported Scopes

The Identity service issues tokens with the following scopes:
ScopeDescriptionUsed By
apiFull API accessWeb, Mobile, Desktop
offline_accessRefresh tokenAll clients
api.organizationPublic organization APIIntegrations
api.pushPush notification registrationMobile
api.licensingLicense validationSelf-hosted
api.scimSCIM provisioningEnterprise SSO
api.secretsSecrets ManagerSM clients
internalInternal service accessNotifications, Events

Client Types

Bitwarden defines several OAuth clients:
Client Definitions
// User-facing clients
web - Web vault
browser - Browser extension
desktop - Desktop application
mobile - Mobile apps
cli - Command-line interface

// Service clients
organization.{guid} - Organization API access
installation.{guid} - Installation access
connector - Directory Connector

Authentication Schemes

From src/Identity/Startup.cs:98:

SSO Integration

The Identity service integrates with the SSO service for enterprise authentication:
SSO Configuration
.AddOpenIdConnect("sso", "Single Sign On", options =>
{
    options.Authority = globalSettings.BaseServiceUri.InternalSso;
    options.ClientId = "oidc-identity";
    options.ClientSecret = globalSettings.OidcIdentityClientKey;
    options.SignInScheme = AuthenticationSchemes.BitwardenExternalCookieAuthenticationScheme;
    options.ResponseType = "code";
    
    options.Events = new OpenIdConnectEvents
    {
        OnRedirectToIdentityProvider = context =>
        {
            // Pass domain_hint and organizationId to SSO service
            context.ProtocolMessage.DomainHint = context.Properties.Items["domain_hint"];
            context.ProtocolMessage.Parameters.Add("organizationId", 
                context.Properties.Items["organizationId"]);
            return Task.FromResult(0);
        }
    };
});

Controllers

The Identity service exposes several endpoints:

SSO Controller

Handles SSO login flows:
/sso/authorize - Initiate SSO login
/sso/login - Process SSO callback
/sso/prevalidate - Validate SSO configuration

Accounts Controller

User account operations:
/accounts/prelogin - Get KDF iteration count
/accounts/register - User registration endpoint

IdentityServer Endpoints

Standard OAuth/OIDC endpoints:
/connect/authorize - Authorization endpoint
/connect/token - Token endpoint
/connect/userinfo - UserInfo endpoint
/connect/introspect - Token introspection
/connect/revoke - Token revocation
/.well-known/openid-configuration - Discovery document

Token Structure

Access Token Claims

Access tokens include the following claims:
{
  "nbf": 1234567890,
  "exp": 1234571490,
  "iss": "https://identity.bitwarden.com",
  "client_id": "web",
  "sub": "{user_id}",
  "auth_time": 1234567890,
  "idp": "bitwarden",
  "premium": "false",
  "email": "[email protected]",
  "email_verified": "true",
  "name": "User Name",
  "orgowner": "{org_id}",
  "device": "{device_id}",
  "scope": ["api", "offline_access"],
  "amr": ["Application"]
}

Refresh Tokens

Refresh tokens are long-lived and must be stored securely by clients.
Refresh tokens enable clients to obtain new access tokens without re-authentication:
Refresh Token Flow
curl -X POST "https://identity.bitwarden.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=web" \
  -d "refresh_token={refresh_token}"

Two-Factor Authentication

The Identity service integrates 2FA into the authentication flow:
1

Primary Authentication

User provides username and password
2

2FA Challenge

Identity service responds with TwoFactorRequired error and available providers
3

2FA Verification

Client resubmits with 2FA code and provider
4

Token Issuance

Identity service issues tokens upon successful 2FA verification
Supported 2FA providers:
  • Authenticator apps (TOTP)
  • Email
  • Duo Security
  • YubiKey
  • FIDO2 WebAuthn

Rate Limiting

The Identity service implements rate limiting to prevent brute force attacks:
Rate Limits
{
  "IpRateLimitOptions": {
    "GeneralRules": [
      {
        "Endpoint": "post:/connect/token",
        "Period": "1m",
        "Limit": 10
      },
      {
        "Endpoint": "post:/accounts/prelogin",
        "Period": "1m",
        "Limit": 10
      }
    ]
  }
}

Middleware Pipeline

From src/Identity/Startup.cs:170:
Request Pipeline
public void Configure(IApplicationBuilder app)
{
    // Security headers
    app.UseMiddleware<SecurityHeadersMiddleware>();
    
    // Path base for self-hosted
    if (globalSettings.SelfHosted)
    {
        app.UsePathBase("/identity");
        app.UseForwardedHeaders(globalSettings);
    }
    
    // Rate limiting (cloud only)
    if (!globalSettings.SelfHosted)
    {
        app.UseMiddleware<CustomIpRateLimitMiddleware>();
    }
    
    // Localization
    app.UseCoreLocalization();
    
    // Static files (login pages, CSS, JS)
    app.UseStaticFiles();
    
    // Routing
    app.UseRouting();
    
    // CORS
    app.UseCors(policy => policy
        .SetIsOriginAllowed(o => CoreHelpers.IsCorsOriginAllowed(o, globalSettings))
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());
    
    // Current context
    app.UseMiddleware<CurrentContextMiddleware>();
    
    // IdentityServer
    app.UseIdentityServer();
    
    // Controllers
    app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
}

Deployment

Environment Variables

GLOBALSETTINGS__SELFHOSTED=true
GLOBALSETTINGS__SQLSERVER__CONNECTIONSTRING=<connection>
GLOBALSETTINGS__IDENTITYSERVER__CERTIFICATETHUMBPRINT=<thumbprint>
GLOBALSETTINGS__OIDCIDENTITYCLIENTKEY=<secret>
GLOBALSETTINGS__BASESERVICEURI__INTERNALSSO=<sso_url>

Docker

docker run -d \
  --name bitwarden-identity \
  -p 5001:5000 \
  -e GLOBALSETTINGS__SelfHosted=true \
  -e GLOBALSETTINGS__SqlServer__ConnectionString="<connection>" \
  bitwarden/identity:latest

Self-Hosted Configuration

In self-hosted deployments, the Identity service runs at /identity path.
Nginx Configuration
location /identity {
    proxy_pass http://identity:5000/identity;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Discovery Document

The Identity service exposes an OpenID Connect discovery document:
curl https://identity.bitwarden.com/.well-known/openid-configuration
Response includes:
  • Authorization endpoint
  • Token endpoint
  • Supported grant types
  • Supported scopes
  • Signing keys (JWKS)

Background Services

From src/Identity/Startup.cs:157:
Hosted Services
if (CoreHelpers.SettingHasValue(globalSettings.ServiceBus.ConnectionString))
{
    services.AddHostedService<Core.HostedServices.ApplicationCacheHostedService>();
}
The cache service synchronizes user permissions and organization data across instances.

Build docs developers (and LLMs) love