Activities of "aziz.bouhejba"

yes it works.. thank you. I guess it's a template issue then?

yes done that, same issue

Reproduction Steps:

  1. Create a new microservice solution.
  2. Create a new tenant.
  3. Log in as the tenant admin.
  4. Create a new role called "Guest".
  5. Create a user named "TestUser" and assign the "Admin" role.
  6. Open an incognito browser and log in as TestUser.
  7. Confirm that TestUser has admin privileges — ✅ expected.
  8. Log out TestUser.
  9. As admin, modify TestUser’s role to "Guest" (remove admin role).
  10. Log in again as TestUser (in incognito).
  11. TestUser still has admin privileges — ❌ unexpected.

Expected Behavior:

After logging out and back in, TestUser should have Guest permissions only, with admin privileges revoked. According to the ABP documentation, role changes should take effect at the next request or at least after reauthentication. For us it doesn't even work with a logout/login

Actual Behavior:

Role changes are not applied even after logout/login. It seems role claims are cached or not refreshed properly.

Only solution we found right now is creating a redis cache service and deleting user cache (not ideal)..

Hi! We're preparing to go live soon—do you have an ETA on when this might be resolved? Thanks in advance!

okay thank you, will wait for an update, have a good day!

Thank you for your answer, I implemented the solution and am still facing the same issue :

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using MyProject.MauiBlazor.Consts;
using MyProject.MauiBlazor.Storage;
using IdentityModel.OidcClient;
using Microsoft.AspNetCore.Components.Authorization;
using Volo.Abp.Account.Pro.Public.MauiBlazor.OAuth;
using LoginResult = Volo.Abp.Account.Pro.Public.MauiBlazor.OAuth.LoginResult;

namespace MyProject.MauiBlazor.OAuth;

public class MyProjectCodeFlowExternalAuthService : ExternalAuthServiceBase
{
    private readonly OidcClient _oidcClient;
    private readonly IStorage _storage;
    private readonly AuthenticationStateProvider _authenticationStateProvider;
    
    public MyProjectCodeFlowExternalAuthService(
        IAccessTokenStore accessTokenStore,
        IStorage storage,
        OidcClient oidcClient,
        AuthenticationStateProvider authenticationStateProvider)
        : base(accessTokenStore)
    {
        _oidcClient = oidcClient;
        _storage = storage;
        _authenticationStateProvider = authenticationStateProvider;
    }

    public override async Task<LoginResult> LoginAsync(LoginInput input)
    {
        var loginResult = await _oidcClient.LoginAsync(new LoginRequest());
        if (loginResult.IsError)
        {
            return LoginResult.Failed(loginResult.Error, loginResult.ErrorDescription);
        }

        await SetTokenCacheAsync(loginResult.AccessToken, loginResult.RefreshToken);

        var currentUser = new ClaimsPrincipal(new ClaimsIdentity(
            new JwtSecurityTokenHandler().ReadJwtToken(loginResult.AccessToken).Claims, 
            authenticationType: AuthenticationType
        ));
        
        (_authenticationStateProvider as MyProjectAuthenticationStateProvider)?.NotifyUserChanged(currentUser);
        
        return LoginResult.Success();
    }

    public override async Task SignOutAsync()
    {
        var logoutResult = await _oidcClient.LogoutAsync();
        await ClearTokenCacheAsync();

        var currentUser = new ClaimsPrincipal(new ClaimsIdentity());

        (_authenticationStateProvider as MyProjectAuthenticationStateProvider)?.NotifyUserChanged(currentUser);
    }

    public async Task<string> GetAccessTokenAsync()
    {
        var token = await _storage.GetAsync(OidcConsts.AccessTokenKeyName);

        if (!token.IsNullOrEmpty())
        {
            var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            if (jwtToken.ValidTo <= DateTime.UtcNow)
            {
                var newToken = await TryRefreshTokenAsync();

                if (!newToken.IsNullOrEmpty())
                {
                    return newToken;
                }
            }
        }

        return token;
    }

    public async Task<string> TryRefreshTokenAsync()
    {
        var refreshToken = await _storage.GetAsync(OidcConsts.RefreshTokenKeyName);

        if (!refreshToken.IsNullOrEmpty())
        {
            var refreshResult = await _oidcClient.RefreshTokenAsync(refreshToken);

            if (!refreshResult.IsError)
            {
                await SetTokenCacheAsync(refreshResult.AccessToken, refreshResult.RefreshToken);
                
                // Also update the authentication state when token is refreshed
                var currentUser = new ClaimsPrincipal(new ClaimsIdentity(
                    new JwtSecurityTokenHandler().ReadJwtToken(refreshResult.AccessToken).Claims, 
                    authenticationType: AuthenticationType
                ));
                (_authenticationStateProvider as MyProjectAuthenticationStateProvider)?.NotifyUserChanged(currentUser);
                
                return refreshResult.AccessToken;
            }
        }

        return string.Empty;
    }

    private async Task SetTokenCacheAsync(string accessToken, string refreshToken)
    {
        await AccessTokenStore.SetAccessTokenAsync(accessToken);
        await _storage.SetAsync(OidcConsts.AccessTokenKeyName, accessToken);
        await _storage.SetAsync(OidcConsts.RefreshTokenKeyName, refreshToken);
    }

    private async Task ClearTokenCacheAsync()
    {
        await AccessTokenStore.SetAccessTokenAsync(null);

        await _storage.RemoveAsync(OidcConsts.AccessTokenKeyName);
        await _storage.RemoveAsync(OidcConsts.RefreshTokenKeyName);
    }
}

And this is the state provider

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
using Volo.Abp.DependencyInjection;

[Volo.Abp.DependencyInjection.Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AuthenticationStateProvider))]
public class MyProjectAuthenticationStateProvider : AuthenticationStateProvider, ISingletonDependency
{
    private ClaimsPrincipal _currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    public void NotifyUserChanged(ClaimsPrincipal user)
    {
        _currentUser = user;
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        return Task.FromResult(new AuthenticationState(_currentUser));
    }
}

Am I doing something wrong?

Also want to mention that I tried keeping TriggerUserChanged that comes from ExternalAuthServiceBase, no success

Showing 21 to 25 of 25 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on October 30, 2025, 06:33