- ABP Framework version: v8.3.1
- UI Type: MVC
- Database System: EF Core ( PostgreSQL)
- Tiered (for MVC) or Auth Server Separated (for Angular): no
- Exception message and full stack trace:
- Steps to reproduce the issue:
I am currently using ABP 8.3.1 Pro version. There is a bug when trying to use tokens created via a custom grant. The main issue from the logs says:
[16:45:33 DBG] AuthenticationScheme: OpenIddict.Validation.AspNetCore was successfully authenticated. [16:45:33 DBG] Get dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 DBG] Filling dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 WRN] SessionId() claim not found for user: a9a8d44f-c8e3-482f-a870-66e93186d540, log out. [16:45:33 DBG] Remove dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 WRN] The token is no longer valid because the user's session expired. [16:45:33 INF] Authorization failed. These requirements were not met: DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
I am removing the dynamic claim right now with this as a temporary solution.
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = false;
});
But I would prefer to keep them for other flows of my application.
I would prefer that my custom grant is not part of dynamic claims (or it could if you provide some code to create sessions appropriately?) This page mentions that there is a Principal Contributor: https://abp.io/docs/latest/modules/identity/session-management#how-it-works So I tried to get rid of it with this command: options.RemoveEventHandler(OpenIddictValidateIdentitySessionValidationHandler.Descriptor); But I still get the error. Maybe there is a flag I can set on the context to avoid getting my principal attached with a sessionId, but I can’t really debug further because all these packages are in the Pro and not compiled with ILDASM.
Can you please provide the following:
- Have a way to turn off session in this token grant
- Have a way to create the session appropriately when creating the token
Supporting code
public class MagicTokenHandler
{
public const string ExtensionGrantName = "magic_token";
public const string MagicTokenKey = "magic_token";
}
// https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs#L49
// https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md
public class MagicTokenExtensionGrant(
IdentityUserManager identityUserManager,
SignInManager<Volo.Abp.Identity.IdentityUser> signInManager,
IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser> userClaimsPrincipalFactory,
AbpOpenIddictClaimsPrincipalManager abpOpenIddictClaimsPrincipalManager,
IOpenIddictScopeManager openIddictScopeManager
) : ITokenExtensionGrant, IScopedDependency
{
public readonly string TOKEN_HANDLER = LinkUserTokenProviderConsts.LinkUserTokenProviderName;
public readonly string TOKEN_PURPOSE = LinkUserTokenProviderConsts.LinkUserLoginTokenPurpose;
public string Name => MagicTokenHandler.ExtensionGrantName;
public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
{
var magicToken = context.Request.GetParameter(MagicTokenHandler.MagicTokenKey).ToString();
if (string.IsNullOrEmpty(magicToken) || string.IsNullOrEmpty(context.Request.Username))
{
return GenericError;
}
var user = await identityUserManager.FindByNameAsync(context.Request.Username);
if (user == null)
{
return GenericError;
}
var result = await identityUserManager.VerifyUserTokenAsync(user, TOKEN_HANDLER, TOKEN_PURPOSE, magicToken);
if (!result)
{
return GenericError;
}
var principal = await signInManager.CreateUserPrincipalAsync(user);
var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
claimsPrincipal.SetScopes(principal.GetScopes());
claimsPrincipal.SetAudiences("VarScanner");
claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));
//For abp version >= 7.3
await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, principal);
return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
}
private async Task<IEnumerable<string>> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray<string> scopes)
{
var resources = new List<string>();
if (!scopes.Any())
{
return resources;
}
await foreach (var resource in openIddictScopeManager.ListResourcesAsync(scopes))
{
resources.Add(resource);
}
return resources;
}
private ForbidResult GenericError => new ForbidResult(
new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest
}!));
}
6 Answer(s)
-
0
hi
Can you try to get an access token and share the
Logs.txt
? also share an access token value.Thanks
liming.ma@volosoft.com
-
0
Hello,
Access Token:
eyJhbGciOiJSUzI1NiIsImtpZCI6IkUzMEMxMUU1MDU2MUM5NDNFNzg5NkE2OTM2RTkyQTg2NTc3QTBEMTAiLCJ4NXQiOiI0d3dSNVFWaHlVUG5pV3BwTnVrcWhsZDZEUkEiLCJ0eXAiOiJhdCtqd3QifQ.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM0My8iLCJleHAiOjE3Mjk2MDk4MzYsImlhdCI6MTcyOTYwNjIzNiwiYXVkIjoiVmFyU2Nhbm5lciIsInNjb3BlIjoib3BlbmlkIiwianRpIjoiZGU1NDIzNjgtN2Y0ZS00MWZjLThiZTEtZmY5YjYyZWE1N2JjIiwic3ViIjoiYTlhOGQ0NGYtYzhlMy00ODJmLWE4NzAtNjZlOTMxODZkNTQwIiwib2lfcHJzdCI6IlZhclNjYW5uZXJfQXBwIiwiY2xpZW50X2lkIjoiVmFyU2Nhbm5lcl9BcHAiLCJvaV90a25faWQiOiIzYTE1YzZiZC05MzU3LWVkNmMtMzQ5Ni1jY2IwOTBjNjA5NmIifQ.4eYHNo8OW1IYIAOMFe8PF3_ITM7bcuRmk6TrXx2Wb8M78_y0MLk5J6j0LE97yUhEtqkePD6MdLgL4cDBJMDONsqpkzQVXmG4-AZVrhp0oWUp4MK6ub3TvCDmFa1U0wN2FdpkUZ7JXRL1K_ix3N3xfOdbJmhgPOueWdFpCGEnHA26oxapd485x5iOPZMdebQ_-iLKAbYngOka53khB_SRH_48Hz47TQ3f44aLikSEAdZqZMpUAELMbc6vlzS56PPSWGsNmmY7tCoOCLXYKHpEVEiOELceRig6F475YWJDBcBOD9YOI_zUTcoADUkmHddeW57n6N39NF19Hr4neaZ4lA
I'm not sure what are the "Logs.txt", but I will send you the output window by email.
-
0
hi
The claims in the access token are:
{ "iss": "https://localhost:44343/", "exp": 1729609836, "iat": 1729606236, "aud": "VarScanner", "scope": "openid", "jti": "de542368-7f4e-41fc-8be1-ff9b62ea57bc", "sub": "a9a8d44f-c8e3-482f-a870-66e93186d540", "oi_prst": "VarScanner_App", "client_id": "VarScanner_App", "oi_tkn_id": "3a15c6bd-9357-ed6c-3496-ccb090c6096b" }
Can you try to call
await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, claimsPrincipal);
?Make sure the
claimsPrincipal
is handled byabpOpenIddictClaimsPrincipalManager
.principal vs claimsPrincipal
var principal = await signInManager.CreateUserPrincipalAsync(user); var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user); claimsPrincipal.SetScopes(principal.GetScopes()); claimsPrincipal.SetAudiences("VarScanner"); claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes())); //For abp version >= 7.3 await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, claimsPrincipal); return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);```
-
0
It does indeed solve the issue. I was able to remove the
RemoveEvent
and re-activate the dynamic claims flag. I copied this code from your documentation here:https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md
Maybe it could be updated.
Thank you for your support.
-
0
Thanks, I will update it.
-
0
https://github.com/abpframework/abp/pull/21167