elsa-core/src/modules/Elsa.Identity
2026-05-21 02:03:06 +02:00
..
Constants Distinguish refresh tokens from API access tokens (#7509) 2026-05-20 14:04:28 +02:00
Contracts Merge remote-tracking branch 'origin/main' into codex/security-identity-secret-hashing 2026-05-20 23:04:02 +02:00
Endpoints Distinguish refresh tokens from API access tokens (#7509) 2026-05-20 14:04:28 +02:00
Entities Remove Elsa.Expressions.Dsl module and related DSL features 2025-06-02 21:52:10 +02:00
Extensions Graceful shutdown for the workflow runtime (drain, pause, recover) (#7424) 2026-05-02 19:27:08 +02:00
Features [codex] Require opt-in for localhost authorization grants (#7498) 2026-05-21 00:40:57 +02:00
HostedServices feat: extend shells integration and modular server support (#7399) 2026-04-18 14:33:34 +02:00
Models Introduce role and user management services (#7297) 2026-02-15 18:50:11 +01:00
Multitenancy Refactor Tenant Resolution to Use Async Local Storage for Operation-wide Access (#6022) 2024-10-12 12:08:09 +02:00
OptionConfigurators [codex] Fail fast on default JWT signing keys (#7496) 2026-05-20 22:30:49 +02:00
Options [codex] Remove production-usable default admin credentials (#7500) 2026-05-20 20:58:03 +02:00
Providers [codex] Remove production-usable default admin credentials (#7500) 2026-05-20 20:58:03 +02:00
Services Address identity review feedback 2026-05-21 02:03:06 +02:00
ShellFeatures [codex] Require opt-in for localhost authorization grants (#7498) 2026-05-21 00:40:57 +02:00
Elsa.Identity.csproj Convert CShells project references to package references in Workflows and Identity modules. 2026-02-19 22:10:02 +01:00
FodyWeavers.xml
IdentityPolicyNames.cs feat: extend shells integration and modular server support (#7399) 2026-04-18 14:33:34 +02:00
README.md Merge remote-tracking branch 'origin/main' into codex/security-identity-secret-hashing 2026-05-21 00:49:15 +02:00

Elsa.Identity

JWT Signing Key Configuration

Identity token signing requires a secure random key. Configure it through environment variables or a secrets manager and keep it out of committed appsettings files.

  • Code-first hosts using Identity:Tokens should set Identity__Tokens__SigningKey.
  • Shell-based hosts should set the shell feature path, for example CShells__Shells__Default__Features__Identity__SigningKey.
  • Production startup rejects missing keys, keys shorter than 32 ASCII characters, and known public defaults. Known public defaults are tolerated only in the explicit Development or Demo environments.

Default Admin User Bootstrap

Elsa supports bootstrapping an initial admin role and user through the DefaultAdminUser feature.

This is the recommended way to initialize identity access now that user-management endpoints are permission-based and no longer rely on the SecurityRoot policy.

See doc/adr/0010-default-admin-user-bootstrap-for-initial-identity-access.md for the architectural decision.

When using shell-based configuration (CShells), configure the DefaultAdminUser shell feature.

Example (appsettings.json):

{
  "CShells": {
    "Shells": [
      {
        "Name": "Default",
        "Features": {
          "Identity": {},
          "DefaultAuthentication": {},
          "DefaultAdminUser": {
            "AdminUserName": "admin",
            "AdminPassword": "REPLACE_WITH_SECURE_BOOTSTRAP_PASSWORD",
            "AdminRoleName": "admin",
            "AdminRolePermissions": ["*"]
          }
        }
      }
    ]
  }
}

This maps to Elsa.Identity.ShellFeatures.DefaultAdminUserFeature and configures DefaultAdminUserOptions at startup.

Legacy feature system (code-first)

When using the legacy feature system (module configuration in code), call UseDefaultAdmin while configuring Identity.

services.AddElsa(elsa =>
{
    elsa
        .UseIdentity(identity =>
        {
            identity.TokenOptions += options =>
            {
                options.SigningKey = builder.Configuration.GetRequiredSection("Identity:Tokens")["SigningKey"]!;
            };

            identity.UseDefaultAdmin(admin => admin
                .WithAdminUserName("admin")
                .WithAdminPassword("REPLACE_WITH_SECURE_BOOTSTRAP_PASSWORD")
                .WithAdminRoleName("admin")
                .WithAdminRolePermissions(new List<string> { "*" }));
        })
        .UseDefaultAuthentication();
});

You can also use the shorthand overload:

identity.UseDefaultAdmin("admin", "REPLACE_WITH_SECURE_BOOTSTRAP_PASSWORD", "admin", new List<string> { "*" });

Operational notes

  • The initializer is idempotent: existing admin role/user are not recreated.
  • Do not keep development defaults in production.
  • Prefer environment variables or a secret manager for admin credentials.
  • After first bootstrap, rotate credentials according to your security policy.
  • Localhost requests no longer satisfy SecurityRoot by default. Legacy localhost bootstrap requires an explicit opt-in: call EnableLocalHostPermissionGrantForSecurityRoot() in code-first configuration or set EnableLocalHostPermissionGrant on the shell DefaultAuthentication feature; prefer DefaultAdminUser instead.

Secret Hashing

New identity passwords, client secrets, and API keys are hashed with PBKDF2-SHA256 using 600,000 iterations, a per-record salt, and version metadata. Existing legacy SHA-256 hashes remain valid and are upgraded opportunistically after a successful user login or API-key validation.