From 10341ca34c32793124ae437877696119a1ac12be Mon Sep 17 00:00:00 2001 From: selman koc <64414348+skoc10@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:11:27 +0300 Subject: [PATCH 1/7] Update version numbers in common.props --- common.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common.props b/common.props index 5e509c5b37..368b7f88a8 100644 --- a/common.props +++ b/common.props @@ -1,8 +1,8 @@ latest - 10.4.0-rc.1 - 5.4.0-rc.1 + 10.5.0-preview + 5.5.0-preview $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ From ec38960f0a2d40f9d990e7ac4a7639cc643f04e0 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 2 May 2026 14:55:24 +0800 Subject: [PATCH 2/7] Add default scopes fallback for client_credentials/password/token_exchange grants --- .../OpenIddict.Demo.Server.csproj | 4 + .../AbpOpenIddictAspNetCoreModule.cs | 7 ++ .../Abp/OpenIddict/AbpOpenIddictOptions.cs | 24 +++++ .../Claims/AbpDefaultScopesHandler.cs | 100 ++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj index 09a185919a..2bc17b4f7c 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj +++ b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj @@ -68,6 +68,10 @@ runtime; build; native; contentfiles; analyzers compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native + + runtime; build; native; contentfiles; analyzers + compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs index 3a9c8109fc..48496874d0 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs @@ -25,9 +25,16 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule Configure(options => { + options.ClaimsPrincipalHandlers.Add(); options.ClaimsPrincipalHandlers.Add(); }); + var preActions = context.Services.GetPreConfigureActions(); + Configure(options => + { + preActions.Configure(options); + }); + Configure(options => { options.ViewLocationFormats.Add("/Volo/Abp/OpenIddict/Views/{1}/{0}.cshtml"); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs index 3339b6d376..9675d7ed6c 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs @@ -25,4 +25,28 @@ public class AbpOpenIddictAspNetCoreOptions /// Set the url of the select account page. /// public string SelectAccountPage { get; set; } = "~/Account/SelectAccount"; + + /// + /// When set to true, the access token issued for the client_credentials grant + /// automatically includes the scopes configured on the client application (permissions + /// prefixed with oi_scp:) when the client does not explicitly request any scope. + /// Default: false. + /// + public bool UseDefaultScopesForClientCredentials { get; set; } + + /// + /// When set to true, the access token issued for the password grant + /// automatically includes the scopes configured on the client application (permissions + /// prefixed with oi_scp:) when the client does not explicitly request any scope. + /// Default: false. + /// + public bool UseDefaultScopesForPassword { get; set; } + + /// + /// When set to true, the access token issued for the urn:ietf:params:oauth:grant-type:token-exchange + /// grant automatically includes the scopes configured on the client application (permissions + /// prefixed with oi_scp:) when the client does not explicitly request any scope. + /// Default: false. + /// + public bool UseDefaultScopesForTokenExchange { get; set; } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs new file mode 100644 index 0000000000..c047742e21 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.OpenIddict; + +public class AbpDefaultScopesHandler : IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency +{ + public ILogger Logger { get; set; } + = NullLogger.Instance; + + public async Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context) + { + var options = context.ScopeServiceProvider + .GetRequiredService>().Value; + + var request = context.OpenIddictRequest; + if (!IsDefaultScopesEnabled(request, options)) + { + return; + } + + if (!context.Principal.GetScopes().IsDefaultOrEmpty) + { + return; + } + + var clientId = request.ClientId; + if (string.IsNullOrEmpty(clientId)) + { + return; + } + + var applicationManager = context.ScopeServiceProvider.GetRequiredService(); + var scopeManager = context.ScopeServiceProvider.GetRequiredService(); + + var application = await applicationManager.FindByClientIdAsync(clientId); + if (application == null) + { + return; + } + + var permissions = await applicationManager.GetPermissionsAsync(application); + var prefix = OpenIddictConstants.Permissions.Prefixes.Scope; + + var scopes = permissions + .Where(p => p.StartsWith(prefix, StringComparison.Ordinal)) + .Select(p => p[prefix.Length..]) + .ToImmutableArray(); + + if (scopes.IsDefaultOrEmpty) + { + return; + } + + Logger.LogDebug( + "Injecting default scopes for client {ClientId} (grant_type {GrantType}): {Scopes}", + clientId, + request.GrantType, + string.Join(", ", scopes)); + + context.Principal.SetScopes(scopes); + + var resources = new List(); + await foreach (var resource in scopeManager.ListResourcesAsync(scopes)) + { + resources.Add(resource); + } + + context.Principal.SetResources(resources); + } + + protected virtual bool IsDefaultScopesEnabled(OpenIddictRequest request, AbpOpenIddictAspNetCoreOptions options) + { + if (request.IsClientCredentialsGrantType()) + { + return options.UseDefaultScopesForClientCredentials; + } + + if (request.IsPasswordGrantType()) + { + return options.UseDefaultScopesForPassword; + } + + if (request.IsTokenExchangeGrantType()) + { + return options.UseDefaultScopesForTokenExchange; + } + + return false; + } +} From ac4855773dd35fd31dab357acdfab31063fe07a8 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 2 May 2026 15:13:52 +0800 Subject: [PATCH 3/7] Use ToListAsync extension for ListResourcesAsync result --- .../Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs index c047742e21..721bb41e78 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; @@ -68,14 +67,7 @@ public class AbpDefaultScopesHandler : IAbpOpenIddictClaimsPrincipalHandler, ITr string.Join(", ", scopes)); context.Principal.SetScopes(scopes); - - var resources = new List(); - await foreach (var resource in scopeManager.ListResourcesAsync(scopes)) - { - resources.Add(resource); - } - - context.Principal.SetResources(resources); + context.Principal.SetResources(await scopeManager.ListResourcesAsync(scopes).ToListAsync()); } protected virtual bool IsDefaultScopesEnabled(OpenIddictRequest request, AbpOpenIddictAspNetCoreOptions options) From bd91cdccc2b388b9fe64b242f3fb539861891fc8 Mon Sep 17 00:00:00 2001 From: Ma Liming Date: Sat, 2 May 2026 15:25:20 +0800 Subject: [PATCH 4/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs index 721bb41e78..82ab4d3bb2 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs @@ -16,7 +16,7 @@ public class AbpDefaultScopesHandler : IAbpOpenIddictClaimsPrincipalHandler, ITr public ILogger Logger { get; set; } = NullLogger.Instance; - public async Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context) + public virtual async Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context) { var options = context.ScopeServiceProvider .GetRequiredService>().Value; From 10b5ed1977b66fbbe60a68cd09bbad20bb6a4ce4 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 2 May 2026 15:39:44 +0800 Subject: [PATCH 5/7] Refine XML doc for password/token_exchange default scopes options --- .../Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs index 9675d7ed6c..f0c2415fb2 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs @@ -35,17 +35,22 @@ public class AbpOpenIddictAspNetCoreOptions public bool UseDefaultScopesForClientCredentials { get; set; } /// - /// When set to true, the access token issued for the password grant - /// automatically includes the scopes configured on the client application (permissions - /// prefixed with oi_scp:) when the client does not explicitly request any scope. + /// When set to true, the token response for the password grant automatically + /// grants the scopes configured on the client application (permissions prefixed with + /// oi_scp:) when the client does not explicitly request any scope. If the configured + /// scopes include openid/profile/email/roles, the corresponding + /// id_token and claim destinations are affected as well. /// Default: false. /// public bool UseDefaultScopesForPassword { get; set; } /// - /// When set to true, the access token issued for the urn:ietf:params:oauth:grant-type:token-exchange - /// grant automatically includes the scopes configured on the client application (permissions - /// prefixed with oi_scp:) when the client does not explicitly request any scope. + /// When set to true, the token response for the + /// urn:ietf:params:oauth:grant-type:token-exchange grant automatically grants the + /// scopes configured on the client application (permissions prefixed with oi_scp:) + /// when the client does not explicitly request any scope. If the configured scopes include + /// openid/profile/email/roles, the corresponding id_token and + /// claim destinations are affected as well. /// Default: false. /// public bool UseDefaultScopesForTokenExchange { get; set; } From 9ad9d988219cb94bb91a1973d3223069a6ca967d Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 4 May 2026 14:00:13 +0800 Subject: [PATCH 6/7] Add default scopes fallback options for client_credentials, password, and token_exchange grants --- docs/en/modules/openiddict.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/en/modules/openiddict.md b/docs/en/modules/openiddict.md index c1ed40ff9f..910bb2c738 100644 --- a/docs/en/modules/openiddict.md +++ b/docs/en/modules/openiddict.md @@ -303,6 +303,18 @@ PreConfigure(options => - `UpdateAbpClaimTypes(default: true)`: Updates `AbpClaimTypes` to be compatible with the Openiddict claims. - `AddDevelopmentEncryptionAndSigningCertificate(default: true)`: Registers (and generates if necessary) a user-specific development encryption/development signing certificate. This is a certificate used for signing and encrypting the tokens and for **development environment only**. You must set it to **false** for non-development environments. +- `UseDefaultScopesForClientCredentials(default: false)`: When set to `true`, the access token issued for the `client_credentials` grant automatically grants the scopes configured on the client application (permissions prefixed with `oi_scp:`) when the client does not explicitly request any scope. +- `UseDefaultScopesForPassword(default: false)`: When set to `true`, the token response for the `password` grant automatically grants the scopes configured on the client application when the client does not explicitly request any scope. If the configured scopes include `openid`/`profile`/`email`/`roles`, the corresponding `id_token` and claim destinations are affected as well. +- `UseDefaultScopesForTokenExchange(default: false)`: When set to `true`, the token response for the `urn:ietf:params:oauth:grant-type:token-exchange` grant automatically grants the scopes configured on the client application when the client does not explicitly request any scope. If the configured scopes include `openid`/`profile`/`email`/`roles`, the corresponding `id_token` and claim destinations are affected as well. + +Example to enable the default-scope fallback for the `client_credentials` grant: + +```csharp +PreConfigure(options => +{ + options.UseDefaultScopesForClientCredentials = true; +}); +``` > `AddDevelopmentEncryptionAndSigningCertificate` cannot be used in applications deployed on IIS or Azure App Service: trying to use them on IIS or Azure App Service will result in an exception being thrown at runtime (unless the application pool is configured to load a user profile). To avoid that, consider creating self-signed certificates and storing them in the X.509 certificates store of the host machine(s). Please refer to: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-development-certificate From a500a3e5af90fc1612434c109ec6f8d074fbb5d5 Mon Sep 17 00:00:00 2001 From: Mansur Besleney Date: Tue, 5 May 2026 08:30:07 +0300 Subject: [PATCH 7/7] Update en.json --- .../Admin/Localization/Resources/en.json | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index bb6c1aeef4..dfe9e530de 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -348,15 +348,39 @@ "CompanySize": "Company size", "DetailTrialLicense": "Details", "Requested": "Requested", + "Pending": "Pending", + "Running": "Running", "Activated": "Activated", "PurchasedToNormalLicense": "Purchased", "Expired": "Expired", "TrialLicenseDeletionWarningMessage": "Are you sure you want to delete the trial license? Trial license, organization, support accounts will be deleted!", "LicenseCategoryFilter": "License category", "Permission:SendWelcomeEmail": "Send Welcome Email", + "Permission:ProvisionExistingOrganizationsAi": "Provision Existing Organizations AI", "SendWelcomeEmail": "Send Welcome Email", "SendWelcomeEmailWarningMessage": "Are you sure you want to send welcome email to the organization members?", "SendWelcomeEmailSuccessMessage": "Welcome email sent successfully!", + "ProvisionExistingOrganizationsAi": "Provision Existing Organizations AI", + "ProvisionExistingOrganizationsAiConfirmation": "This will enable AI assisted development for all active organizations, grant included AI credits, and provision provider keys in the background. Do you want to continue?", + "DeleteExistingOrganizationsAiCredentials": "Delete Existing Organizations AI Keys", + "DeleteExistingOrganizationsAiCredentialsConfirmation": "This will revoke existing OpenRouter keys referenced by organizations and remove stored AI credentials from the database so provisioning can be retried. Do you want to continue?", + "ExistingOrganizationsAiOperationAlreadyRunning": "Another existing organizations AI operation is already running.", + "ExistingOrganizationsAiBackfillAlreadyRunning": "An existing organizations AI provisioning job is already running.", + "ExistingOrganizationsAiBackfillMissingManagementApiKey": "OpenRouter management API key is not configured for the admin application. Configure AiAssistedDevelopment:Providers:OpenRouter:ManagementApiKey before starting this operation.", + "NoActiveOrganizationsFoundForAiBackfill": "No active organizations were found for AI provisioning.", + "NoOrganizationsFoundForAiCredentialCleanup": "No organizations with AI credentials were found for cleanup.", + "ExistingOrganizationsAiBackfillNotFound": "The existing organizations AI provisioning operation was not found.", + "ExistingOrganizationsAiBackfillCompleted": "Existing organizations AI provisioning completed successfully.", + "ExistingOrganizationsAiBackfillFailed": "Existing organizations AI provisioning failed.", + "ExistingOrganizationsAiCredentialCleanupCompleted": "Existing organizations AI credential cleanup completed successfully.", + "ExistingOrganizationsAiCredentialCleanupFailed": "Existing organizations AI credential cleanup failed.", + "CurrentOrganization": "Current organization", + "Processed": "Processed", + "Succeeded": "Succeeded", + "Failed": "Failed", + "Cancelled": "Cancelled", + "CompletedAt": "Completed at", + "LastError": "Last error", "Activate": "Activate", "ActivateTrialLicenseWarningMessage": " When you activate a trial license, a welcome e-mail will be sent to the user. Do you want to activate it?", "ActivateTrialLicenseSuccessMessage": "Activated successfully and the welcome e-mail sent to the organization members.",