Open Closed

Questions about distinguishing and handling external login #9895


User avatar
0
papusa created

Hi, I previously opened a ticket regarding external login with BankID, and I now have three additional questions:

Recognizing login type

  • Is it possible to determine whether the user logged in with a local account or via an external login (e.g., BankID)? I'd like to make certain decisions based on the login method used.

Adding login type claim

  • Is it possible to include a custom claim in both the access_token and the id_token?

Handling BankID-only actions There are some actions in my application that must only be allowed when a user is authenticated via BankID (external login).

  • If the user does not yet have an external login, they should be prompted to add it.
  • When a user adds an external login, it goes through the BankID login flow. However, when the request returns to the ABP application, the claims contributors are missing, so I cannot add any claim that marks the user as BankID-authenticated.
  • This results in the user having to authenticate with BankID twice, which is not ideal.

Is there a recommended way to handle this scenario to avoid requiring double BankID authentication?


4 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • To determine if a user logged in with a local account or via an external login (such as BankID), you can inspect the user's login providers. ABP's Identity system stores external login information in the user logins table. You can check if the current user has a login with the external provider (e.g., "BankID") to distinguish the login type. The ICurrentUser service provides access to the current user's claims, but you may need to query the user manager for external login info.

    • To include a custom claim in both the access_token and id_token, you can use claims contributors in ABP. Implement IAbpClaimsPrincipalContributor and register it. In your contributor, add a custom claim (e.g., "login_type") based on the authentication context. This claim will be included in the generated tokens if added during the authentication process.

      Example:

    public class LoginTypeClaimsContributor : IAbpClaimsPrincipalContributor
      {
          public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
          {
              // Example: Add a claim based on login provider
              var loginType = context.Principal?.FindFirst("amr")?.Value ?? "local";
              context.Identity.AddClaim(new Claim("login_type", loginType));
              return Task.CompletedTask;
          }
      }
    
    • For BankID-only actions, the recommended approach is:

      1. When a user must perform a BankID-only action, check if they have a BankID external login associated.
      2. If not, prompt them to add it (initiate the external login flow).
      3. To avoid double authentication, ensure your claims contributor or token generation logic can detect the BankID login context during the external login callback. You may need to persist a flag or use the authentication properties to pass context between the external login initiation and callback, so you can add the correct claim in a single flow.

      The key is to ensure your claims contributor has enough context to know the login was via BankID during the external login callback, so you can add the "BankID-authenticated" claim immediately.

    Sources:

    • https://abp.io/docs/latest/CurrentUser
    • https://abp.io/community/articles/km5dw6g1
    • https://abp.io/community/articles/4603b9cf

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    papusa created

    To determine if a user logged in with a local account or via an external login (such as BankID), you can inspect the user's login providers. ABP's Identity system stores external login information in the user logins table.

    As I understand it, this only shows which providers are associated with the user (from the user logins table), not which provider was actually used for the current login session. Is there a way to detect the login type of the current session?

    To include a custom claim in both the access_token and id_token, you can use claims contributors in ABP. Implement IAbpClaimsPrincipalContributor and register it. In your contributor, add a custom claim (e.g., "login_type") based on the authentication context. This claim will be included in the generated tokens if added during the authentication process.

    I have already implemented a claims contributor. But is this the recommended approach? I noticed it is executed four (4) times when a user logs in from Angular. Also, it does not add the claim to the id_token or access_token received on the client. This was partially solved by the suggested IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext> implementation from my previous ticket, but that only adds the claim to the access_token, which is not very convenient on the client side.

    The AI answer didn’t really address my third question either. Could you please clarify the recommended way to handle the scenario where a user adds a new external login?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Is it possible to determine whether the user logged in with a local account or via an external login (e.g., BankID)? I'd like to make certain decisions based on the login method used.

    You can use a custom claim to check it. eg nationalidentitynumber then try to get this claim from CurrentUser.

    Is it possible to include a custom claim in both the access_token and the id_token?

    You can check the BankID platform to see if it supports adding custom claims for a user.

    Thanks.

  • User Avatar
    0
    papusa created

    You can use a custom claim to check it. eg nationalidentitynumber then try to get this claim from CurrentUser.

    Here is my claims contributor:

    public class BankIdClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
    {
        private readonly AbpSignInManager _signInManager;
    
        public BankIdClaimsPrincipalContributor(AbpSignInManager signInManager)
        {
            _signInManager = signInManager;
        }
    
        public async Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
        {
            var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
            
            var externalLogin = await _signInManager.GetExternalLoginInfoAsync();
            if (externalLogin == null)
            {
                // Contributor is executed 4 times. Last 2 times externalLogin is null.
                // It results in 2 "isbankidauthenticated" claims, one has value of false and another is true.
                identity?.AddClaim(new Claim("isbankidauthenticated", false.ToString().ToLower()));
                return;
            }
            
            var isBankIdAuthenticated = externalLogin.LoginProvider == "Criipto";
            var claim = new Claim("isbankidauthenticated", isBankIdAuthenticated.ToString().ToLower());
            identity?.AddClaim(claim);
        }
    }
    

    I noticed that it gets executed 4 times. Is this the expected behavior? This causes an issue because I cannot reliably set my claim value to false.

    You can check the BankID platform to see if it supports adding custom claims for a user.

    I don’t quite understand how BankID is related here. As far as I know, the claims are set within the ABP application itself. Am I missing something? Previously, you suggested implementing IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>. This works, but it only adds the claim to the access_token. How can I also include the claim in the id_token?

    public class BankIdOpenIddictServerHandler :  IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>
    {
        public static OpenIddictServerHandlerDescriptor Descriptor { get; }
            = OpenIddictServerHandlerDescriptor.CreateBuilder<OpenIddictServerEvents.ProcessSignInContext>()
                .UseSingletonHandler<BankIdOpenIddictServerHandler>()
                .SetOrder(100_000)
                .SetType(OpenIddictServerHandlerType.Custom)
                .Build();
    
        public async ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignInContext context)
        {
            if (context.EndpointType != OpenIddictServerEndpointType.Authorization ||
                context.AuthorizationCodePrincipal == null)
            {
                return;
            }
    
            var httpContext = context.Transaction.GetHttpRequest()?.HttpContext;
            if (httpContext == null)
            {
                return;
            }
    
            var identity = await httpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
            if (identity.Principal == null)
            {
                return;
            }
    
            var bankIdClaim = identity.Principal.FindFirst("isbankidauthenticated");
            if (bankIdClaim != null)
            {
                context.AuthorizationCodePrincipal.AddClaim("isbankidauthenticated", bankIdClaim.Value);
            }
        }
    }
    
Learn More, Pay Less
33% OFF
All Trainings!
Get Your Deal
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 16, 2025, 10:35