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:Tokensshould setIdentity__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
DevelopmentorDemoenvironments.
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.
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> { "*" });- 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
SecurityRootby default. Legacy localhost bootstrap requires an explicit opt-in: callEnableLocalHostPermissionGrantForSecurityRoot()in code-first configuration or setEnableLocalHostPermissionGranton the shellDefaultAuthenticationfeature; preferDefaultAdminUserinstead.
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.