Configuration Reference
Full configuration example
Section titled “Full configuration example”{ "OpenIddict": { "Issuer": "https://auth.example.com", "UseReferenceTokens": false, "EnableEntityCaching": false, "RequirePar": false, "EnableTokenExchange": false,
"Client": { "AutoRegisterExternalUsers": true, "Providers": [ { "Name": "Google", "ClientId": "xxx.apps.googleusercontent.com", "ClientSecret": "GOCSPX-xxx", "Scopes": ["openid", "profile", "email"] }, { "Name": "Microsoft", "ClientId": "00000000-0000-0000-0000-000000000000", "ClientSecret": "xxx", "Scopes": ["openid", "profile", "email"] }, { "Name": "GitHub", "ClientId": "Iv1.xxx", "ClientSecret": "xxx", "Scopes": ["openid", "user:email"] } ] },
"Seeding": { "Applications": [ { "ClientId": "my-spa", "ClientSecret": null, "DisplayName": "My SPA (PKCE)", "Permissions": [ "ept:authorization", "ept:token", "ept:logout", "gt:authorization_code", "gt:refresh_token", "scp:openid", "scp:profile", "scp:email", "scp:offline_access" ], "RedirectUris": ["https://app.example.com/callback"], "PostLogoutRedirectUris": ["https://app.example.com"] }, { "ClientId": "my-api", "ClientSecret": "super-secret-should-come-from-vault", "DisplayName": "My API (Client Credentials)", "Permissions": [ "ept:token", "gt:client_credentials", "scp:api" ], "RedirectUris": [], "PostLogoutRedirectUris": [] } ], "Scopes": [ { "Name": "api", "DisplayName": "API Access", "Resources": ["my-api"] } ] },
"Passkeys": { "ServerDomain": "example.com", "AuthenticatorTimeout": "00:05:00", "ChallengeSize": 32 } }}GranitOpenIddictOptions
Section titled “GranitOpenIddictOptions”Configuration section: OpenIddict
Bound in: GranitOpenIddictModule.ConfigureServices()
| Property | Type | Default | Description |
|---|---|---|---|
Issuer | Uri? | null | Explicit OIDC issuer URI. When null, the issuer is inferred from the incoming request URL. Set explicitly for multi-node deployments behind a load balancer. |
UseReferenceTokens | bool | false | Issue opaque reference tokens instead of self-contained JWTs. Reference tokens are validated against the database on every API request, enabling instant revocation. Required for SOC2 / ISO 27001 strict compliance. Trade-off: +1 DB round-trip per API call. |
EnableEntityCaching | bool | false | Enable OpenIddict’s built-in entity caching. Disable in multi-tenant deployments — the cache uses ClientId as the sole key, which causes cross-tenant pollution when two tenants have the same ClientId. |
RequirePar | bool | false | Require Pushed Authorization Requests (RFC 9126) for all authorization code flows. The /connect/par endpoint is always available; when true, direct authorization requests without a request_uri are rejected. Required for FAPI 2.0 compliance. |
EnableTokenExchange | bool | false | Enable OAuth 2.0 Token Exchange (RFC 8693). Registers the urn:ietf:params:oauth:grant-type:token-exchange grant type for microservice delegation and impersonation flows. Clients must have the gt:token_exchange permission. |
EnableFapi2Profile | bool | false | Enable the FAPI 2.0 Security Profile. When true, enforces all server-side FAPI 2.0 constraints: RequirePar is set to true, authorization code lifetime is reduced to 60 seconds, and PKCE S256 remains enforced. BFF and resource server must also be configured separately (UseDPoP, ClientAuthenticationMethod: PrivateKeyJwt, RequireDPoP). |
Example:
{ "OpenIddict": { "Issuer": "https://auth.example.com", "UseReferenceTokens": false, "EnableEntityCaching": false, "RequirePar": false, "EnableFapi2Profile": false }}GranitOpenIddictClientOptions
Section titled “GranitOpenIddictClientOptions”Configuration section: OpenIddict:Client
Bound in: GranitOpenIddictModule.ConfigureServices()
| Property | Type | Default | Description |
|---|---|---|---|
AutoRegisterExternalUsers | bool | true | Auto-create a GranitUser on first login via an external provider. When false, returns 403 if no existing account matches the email. |
Providers | ExternalProviderOptions[] | [] | External login providers to configure. |
ExternalProviderOptions
Section titled “ExternalProviderOptions”| Property | Type | Default | Description |
|---|---|---|---|
Name | string | "" | Provider name: "Google", "Microsoft", or "GitHub". |
ClientId | string | "" | OAuth 2.0 client ID obtained from the provider’s developer console. |
ClientSecret | string | "" | OAuth 2.0 client secret. Use Granit.Vault in production. |
Scopes | string[] | ["openid", "profile", "email"] | OAuth scopes to request from the provider. |
Example:
{ "OpenIddict": { "Client": { "AutoRegisterExternalUsers": true, "Providers": [ { "Name": "Google", "ClientId": "xxx.apps.googleusercontent.com", "ClientSecret": "GOCSPX-xxx", "Scopes": ["openid", "profile", "email"] } ] } }}GranitOpenIddictSeedingOptions
Section titled “GranitOpenIddictSeedingOptions”Configuration section: OpenIddict:Seeding
Bound in: GranitOpenIddictModule.ConfigureServices() and
GranitOpenIddictEntityFrameworkCoreModule.ConfigureServices()
| Property | Type | Default | Description |
|---|---|---|---|
Applications | OidcApplicationSeedDescriptor[] | [] | OIDC applications to seed at startup. Idempotent upsert based on ClientId. |
Scopes | OidcScopeSeedDescriptor[] | [] | OIDC scopes to seed at startup. Idempotent upsert based on Name. |
OidcApplicationSeedDescriptor
Section titled “OidcApplicationSeedDescriptor”| Property | Type | Description |
|---|---|---|
ClientId | string | Unique client identifier (upsert key). |
ClientSecret | string? | Client secret. null for public clients (SPAs). Encrypted before persistence. |
DisplayName | string | Human-readable display name. |
Permissions | string[] | OpenIddict permissions (e.g., ept:token, gt:authorization_code, scp:openid). |
RedirectUris | string[] | Allowed redirect URIs after authorization. |
PostLogoutRedirectUris | string[] | Allowed redirect URIs after logout. |
SigningKeyJwk | string? | JWK Set containing the client’s public key for private_key_jwt authentication (RFC 7523). |
OidcScopeSeedDescriptor
Section titled “OidcScopeSeedDescriptor”| Property | Type | Description |
|---|---|---|
Name | string | Unique scope name (upsert key). |
DisplayName | string | Human-readable display name. |
Resources | string[] | Resources associated with this scope (audience values). |
OpenIddict permission reference
Section titled “OpenIddict permission reference”| Prefix | Meaning | Examples |
|---|---|---|
ept: | Endpoint | ept:authorization, ept:token, ept:logout, ept:introspection, ept:revocation, ept:device |
gt: | Grant type | gt:authorization_code, gt:client_credentials, gt:refresh_token, gt:urn:ietf:params:oauth:grant-type:device_code |
rst: | Response type | rst:code, rst:id_token, rst:token |
scp: | Scope | scp:openid, scp:profile, scp:email, scp:roles, scp:offline_access, custom scopes |
Example (SPA with PKCE):
{ "ClientId": "my-spa", "ClientSecret": null, "DisplayName": "My SPA", "Permissions": [ "ept:authorization", "ept:token", "ept:logout", "gt:authorization_code", "gt:refresh_token", "scp:openid", "scp:profile", "scp:email", "scp:offline_access" ], "RedirectUris": ["https://app.example.com/callback"], "PostLogoutRedirectUris": ["https://app.example.com"]}Example (M2M with Client Credentials):
{ "ClientId": "my-api", "ClientSecret": "super-secret-should-come-from-vault", "DisplayName": "My API", "Permissions": [ "ept:token", "gt:client_credentials", "scp:api" ], "RedirectUris": [], "PostLogoutRedirectUris": []}GranitPasskeyOptions
Section titled “GranitPasskeyOptions”Configuration section: OpenIddict:Passkeys
Bound in: GranitOpenIddictModule.ConfigureServices() and
GranitOpenIddictEntityFrameworkCoreModule.ConfigureServices()
| Property | Type | Default | Description |
|---|---|---|---|
ServerDomain | string | "" | WebAuthn Relying Party ID (domain). Required when passkeys are enabled. Must match the domain where the application is hosted (e.g., "example.com"). |
AuthenticatorTimeout | TimeSpan | 00:05:00 | Timeout for authenticator operations (registration and assertion ceremonies). |
ChallengeSize | int | 32 | Challenge size in bytes for WebAuthn operations. |
Example:
{ "OpenIddict": { "Passkeys": { "ServerDomain": "example.com", "AuthenticatorTimeout": "00:05:00", "ChallengeSize": 32 } }}GranitKeyRotationOptions
Section titled “GranitKeyRotationOptions”Bound from: OpenIddict:KeyRotation section
| Property | Type | Default | Description |
|---|---|---|---|
Enabled | bool | false | Enable automatic key rotation. When disabled, ephemeral keys are used. |
KeyLifetime | TimeSpan | 90 days | How long a signing key remains active before rotation. |
GracePeriod | TimeSpan | 14 days | How long a retired key remains in JWKS for token verification. Should be >= max token lifetime. |
RotationLeadTime | TimeSpan | 7 days | How far in advance a new key is generated before the active key expires. |
RsaKeySize | int | 2048 | RSA key size in bits. Use 4096 for higher security requirements. |
SigningAlgorithm | string | RS256 | The JWT signing algorithm. |
{ "OpenIddict": { "KeyRotation": { "Enabled": true, "KeyLifetime": "90.00:00:00", "GracePeriod": "14.00:00:00", "RotationLeadTime": "7.00:00:00", "RsaKeySize": 2048, "SigningAlgorithm": "RS256" } }}OpenIddictEndpointsOptions
Section titled “OpenIddictEndpointsOptions”Configured in: MapGranitOpenIddict() lambda
| Property | Type | Default | Description |
|---|---|---|---|
AccountRoutePrefix | string | "account" | Route prefix for account self-service endpoints. |
AdminRoutePrefix | string | "admin" | Route prefix for admin management endpoints. |
AccountTagName | string | "Account" | OpenAPI tag for account endpoints. |
AdminTagName | string | "Administration" | OpenAPI tag for admin endpoints. |
Example:
api.MapGranitOpenIddict(options =>{ options.AccountRoutePrefix = "account"; options.AdminRoutePrefix = "admin";});GranitOpenIddictDbProperties
Section titled “GranitOpenIddictDbProperties”Static properties for table naming. Must be set before ConfigureServices
completes — EF Core caches the compiled model after first use.
| Property | Type | Default | Description |
|---|---|---|---|
DbTablePrefix | string | "openiddict_" | Table name prefix for all Identity and OpenIddict tables. |
DbSchema | string? | null | Database schema. null uses the provider’s default schema. |
Example:
// Before builder.Build()GranitOpenIddictDbProperties.DbTablePrefix = "auth_";GranitOpenIddictDbProperties.DbSchema = "identity";Per-tenant settings (Granit.Settings)
Section titled “Per-tenant settings (Granit.Settings)”These settings are registered via OpenIddictSettingDefinitionProvider (auto-discovered
by GranitSettingsModule) and configurable per-tenant at runtime via the Settings
admin API. No redeployment needed.
| Setting key | Type | Default | Description |
|---|---|---|---|
OpenIddict.AccessTokenLifetime | TimeSpan | 01:00:00 (1 hour) | Access token lifetime. |
OpenIddict.RefreshTokenLifetime | TimeSpan | 14.00:00:00 (14 days) | Refresh token lifetime. |
OpenIddict.AuthCodeLifetime | TimeSpan | 00:05:00 (5 minutes) | Authorization code lifetime. |
OpenIddict.MaxLoginAttempts | int | 5 | Maximum failed login attempts before account lockout. |
OpenIddict.IdleSessionTimeout | int | 0 (disabled) | Idle session timeout in minutes. 0 disables the feature. |
Setting constants are defined in OpenIddictSettingNames:
public static class OpenIddictSettingNames{ public const string AccessTokenLifetime = "OpenIddict.AccessTokenLifetime"; public const string RefreshTokenLifetime = "OpenIddict.RefreshTokenLifetime"; public const string AuthCodeLifetime = "OpenIddict.AuthCodeLifetime"; public const string MaxLoginAttempts = "OpenIddict.MaxLoginAttempts"; public const string IdleSessionTimeout = "OpenIddict.IdleSessionTimeout";}Feature flags (Granit.Features)
Section titled “Feature flags (Granit.Features)”Feature flags are registered via OpenIddictFeatureDefinitionProvider (auto-discovered
by GranitFeaturesModule). Resolution order: Tenant > Plan > Default.
| Feature key | Default | Description |
|---|---|---|
OpenIddict.TwoFactor | true | TOTP-based two-factor authentication. |
OpenIddict.DeviceFlow | false | OAuth 2.0 Device Authorization Grant (RFC 8628). |
OpenIddict.ExternalLogins | true | External login providers (Google, Microsoft, GitHub). |
OpenIddict.PkceRequired | true | PKCE requirement for all authorization code flows. |
OpenIddict.Passkeys | false | WebAuthn/FIDO2 passwordless authentication. |
OpenIddict.JarRequired | false | Require JWT-Secured Authorization Requests (RFC 9101). |
Feature constants are defined in OpenIddictFeatureNames:
public static class OpenIddictFeatureNames{ public const string TwoFactor = "OpenIddict.TwoFactor"; public const string DeviceFlow = "OpenIddict.DeviceFlow"; public const string ExternalLogins = "OpenIddict.ExternalLogins"; public const string PkceRequired = "OpenIddict.PkceRequired"; public const string Passkeys = "OpenIddict.Passkeys"; public const string JarRequired = "OpenIddict.JarRequired";}Permissions
Section titled “Permissions”All 19 permission constants are defined in OpenIddictPermissions and follow the
[Group].[Resource].[Action] convention. They are registered via
OpenIddictPermissionDefinitionProvider (auto-discovered by GranitAuthorizationModule).
| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Users.Read | OpenIddict.Users.Read | List and view users |
OpenIddictPermissions.Users.Create | OpenIddict.Users.Create | Create new users |
OpenIddictPermissions.Users.Manage | OpenIddict.Users.Manage | Update user details |
OpenIddictPermissions.Users.Delete | OpenIddict.Users.Delete | Soft-delete users |
OpenIddictPermissions.Users.Impersonate | OpenIddict.Users.Impersonate | Impersonate a user |
| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Roles.Read | OpenIddict.Roles.Read | List and view roles |
OpenIddictPermissions.Roles.Create | OpenIddict.Roles.Create | Create new roles |
OpenIddictPermissions.Roles.Delete | OpenIddict.Roles.Delete | Delete roles |
Groups
Section titled “Groups”| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Groups.Read | OpenIddict.Groups.Read | List and view groups |
OpenIddictPermissions.Groups.Create | OpenIddict.Groups.Create | Create new groups |
OpenIddictPermissions.Groups.Manage | OpenIddict.Groups.Manage | Manage group details and membership |
OpenIddictPermissions.Groups.Delete | OpenIddict.Groups.Delete | Delete groups |
Applications
Section titled “Applications”| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Applications.Read | OpenIddict.Applications.Read | List and view OIDC applications |
OpenIddictPermissions.Applications.Manage | OpenIddict.Applications.Manage | Create, update, and delete OIDC applications |
OpenIddictPermissions.Applications.Rotate | OpenIddict.Applications.Rotate | Rotate client secrets |
Scopes
Section titled “Scopes”| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Scopes.Read | OpenIddict.Scopes.Read | List and view OIDC scopes |
OpenIddictPermissions.Scopes.Manage | OpenIddict.Scopes.Manage | Create, update, and delete OIDC scopes |
Authorizations
Section titled “Authorizations”| Constant | Value | Description |
|---|---|---|
OpenIddictPermissions.Authorizations.Read | OpenIddict.Authorizations.Read | List and view OIDC authorizations |
OpenIddictPermissions.Authorizations.Revoke | OpenIddict.Authorizations.Revoke | Revoke OIDC authorizations |
ASP.NET Core Identity defaults
Section titled “ASP.NET Core Identity defaults”Configured by AddGranitOpenIddict():
options.User.RequireUniqueEmail = true;options.Lockout.MaxFailedAccessAttempts = 5; // from GranitLockoutOptionsoptions.Lockout.DefaultLockoutTimeSpan = ...; // from GranitLockoutOptions.BaseLockoutDurationoptions.SignIn.RequireConfirmedEmail = true;These values are read from GranitLockoutOptions (section Identity:Lockout).
The MaxLoginAttempts runtime setting (OpenIddict.MaxLoginAttempts) overrides
MaxFailedAccessAttempts per-tenant.
Lockout with exponential backoff
Section titled “Lockout with exponential backoff”Granit replaces ASP.NET Core Identity’s fixed lockout duration with exponential
backoff via GranitUserManager. Each consecutive lockout doubles the duration,
capped at MaxLockoutDuration (default: 2 hours).
{ "Identity": { "Lockout": { "MaxFailedAccessAttempts": 5, "BaseLockoutDuration": "00:05:00", "MaxLockoutDuration": "02:00:00", "ExponentialBase": 2.0 } }}| Option | Type | Default | Description |
|---|---|---|---|
MaxFailedAccessAttempts | int | 5 | Failed attempts before lockout. |
BaseLockoutDuration | TimeSpan | 5 min | Duration of the first lockout. |
MaxLockoutDuration | TimeSpan | 2 hours | Maximum lockout duration (cap). |
ExponentialBase | double | 2.0 | Multiplier for each consecutive lockout. |
See Account lockout for the full security architecture (anti-enumeration, timing attack prevention, self-service unlock).