User Management
When to Use This Skill
- Adding user management to a Duende IdentityServer project
- Setting up passwordless authentication (OTP, TOTP, passkeys)
- Configuring storage providers (PostgreSQL, SQL Server, SQLite)
- Integrating User Management with IdentityServer for claims and login/logout
- Managing user profiles, roles, and groups
- Migrating users from ASP.NET Identity
Core Principles
- Duende User Management is passwordless-first — OTP email/SMS is the default flow
- Requires
Duende.UserManagement.IdentityServer8NuGet package + .NET 10 - Storage is document-based (no EF migrations needed) — schema auto-creates at startup
- Configuration goes inside
AddUserManagement(), not at top level - Use
app.UseIdentityServer()(notUseAuthentication()separately)
Docs: https://docs.duendesoftware.com/identityserver/usermanagement
Setup
1. Add Packages
2. Configure Program.cs
3. OTP Dispatcher
Console (development):
SMTP (production):
Authentication Methods
IdentityServer Integration
AddUserManagement() is called on the IdentityServer builder — it automatically:
- Registers
IProfileServicefor claims delivery - Handles login/logout flows
- Maps user attributes to identity token claims
Claims Mapping
User profile attributes are mapped to claims based on requested scopes:
openid→subprofile→name,given_name,family_name, etc.email→email,email_verified
Custom attributes are available through custom identity resources.
Storage
Storage is document-based — no EF Core migrations needed. Call IDatabaseSchema.CreateIfNotExistsAsync() at startup to ensure schema exists.
User Lifecycle
- Creation: Users are created on first authentication (passwordless) or via admin APIs
- Profiles: Custom attributes stored as key-value pairs, organized in attribute groups
- Roles & Groups: RBAC support with group membership and role inheritance
- Deletion: Full user deletion with cascade
Migration from ASP.NET Identity
Key points:
- Imports users, roles, and claims from existing ASP.NET Identity tables
- Password hashes are preserved (users can still log in with existing passwords)
- Migration runs once; subsequent runs skip already-imported users
- After migration, users can enroll in passwordless methods
Common Anti-Patterns
❌ Configuring storage outside AddUserManagement() — storage config must be inside the options lambda
❌ Using UseAuthentication() instead of UseIdentityServer() — IdentityServer middleware handles auth
❌ Skipping CreateIfNotExistsAsync() — database tables won't exist on first run
❌ Using in-memory storage in production — data is lost on restart
Common Pitfalls
- Storage configuration location:
AddSqliteStore()/AddPostgreSqlStore()must be called inside theAddUserManagement(options => { })lambda, not on the top-level builder. - .NET 10 required: User Management requires .NET 10 SDK or later.
- OTP dispatcher required: Without an
IOtpDispatcher, the default OTP flow cannot send codes. RegisterConsoleOtpDispatcherfor development. - LoginUrl/LogoutUrl: Must be set in IdentityServer options to point to your account pages.
- Schema creation: Call
IDatabaseSchema.CreateIfNotExistsAsync()before the app starts handling requests.
Related Skills
identityserver-configuration— IdentityServer host configuration and optionsidentityserver-ui-flows— Login/logout UI flowsidentityserver-upgrade-v7-to-v8— Migration guide for v8 (includes User Management as new feature)aspnetcore-authentication— ASP.NET Core authentication fundamentals


