Activities of "papusa"

I can definitely create and share a demo project with you, but please note that I won’t be able to include the external login provider credentials (like the client secret), since those are sensitive. Would that still work for you?

I can provide a test user (test identity number), or you're welcome to generate one yourself using this link: https://ra-preprod.bankidnorge.no/#/generate We're using Criipto for Norwegian BankID. You can get test account for free.

That said, I assumed the issue wasn't specific to BankID, and that any external login provider would be sufficient for testing in a demo setup. Please let me know how you'd prefer to proceed!

Previously, I was using HttpContextAccessor.HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme) to retrieve the external claims principal.

After reviewing the link you provided, I switched to using SignInManager, but the behavior hasn't changed. When logging into the Angular app, the external login is null, and I'm not receiving the expected claims when calling the API from the Angular front end.

Here's the code for my IAbpClaimsPrincipalContributor implementation. Could you please take a look and let me know if there's anything wrong or missing?

public class BankIdClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency { private readonly SignInManager<IdentityUser> _signInManager;

public BankIdClaimsPrincipalContributor(SignInManager&lt;IdentityUser&gt; signInManager)
{
    _signInManager = signInManager;
}

public async Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
    var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
    
    var externalLogin = await _signInManager.GetExternalLoginInfoAsync();
    if (externalLogin == null)
    {
        identity?.AddClaim(new Claim("isbankidauthenticated", false.ToString().ToLower()));
        return;
    }
    
    var authenticationTypeClaim = externalLogin.Principal.FindFirst(Claims.BankId.AuthenticationType);
    var isBankIdAuthenticated = authenticationTypeClaim is { Value: Claims.BankId.NorwegianAuthenticationTypeValue };
    identity?.AddClaim(new Claim("isbankidauthenticated", isBankIdAuthenticated.ToString().ToLower()));

    if (!isBankIdAuthenticated)
    {
        return;
    }

    ForwardClaim("socialno", "nationalidentitynumber");
    ForwardClaim("dateofbirth", "dateofbirth");
    
    return;
    
    void ForwardClaim(string bankIdClaimType, string claimType)
    {
        var claim = externalLogin.Principal.FindFirst(bankIdClaimType);
        if (claim != null)
        {
            identity?.AddClaim(new Claim(claimType, claim.Value));
        }
    }
}

}


I think it might be more convenient if you could create a demo project yourself with the setup you have in mind. :)

Hi, Thanks for your response.

Could you clarify the purpose of the demo project? I’m unable to share external provider credentials, so I'm not sure how useful it would be in this case.

If you’re familiar with retrieving additional claims, perhaps you could share a demo that demonstrates the solution? :)

Here is how external provider is added in our app:

private void ConfigureExternalProviders(ServiceConfigurationContext context, IConfiguration configuration)
{
    var criiptoAuthority = configuration["Authentication:Criipto:Authority"];
    var criiptoClientId = configuration["Authentication:Criipto:ClientId"];
    var criiptoClientSecret = configuration["Authentication:Criipto:ClientSecret"];
    
    context.Services.AddAuthentication()
        .AddOpenIdConnect("Criipto", "BankID", options =>
        {
            options.ClientId = criiptoClientId;
            options.ClientSecret = criiptoClientSecret;
            options.Authority = criiptoAuthority;
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.CallbackPath = new PathString("/signin-bankid");

            options.Scope.Add("ssn");
            
            options.ClaimActions.MapJsonKey("socialno", "socialno");
            options.ClaimActions.MapJsonKey("dateofbirth", "dateofbirth");
        });
}

AI answer didn't solve the problem.

We have integrated an external login provider (BankID) into our ABP application v9 (Layered/Angular/No separate auth). Login flow works, but two issues remain regarding claims handling and distinguishing login type:

  1. Forwarding External Claims
  • During the external login callback, BankID provides additional claims (e.g., national identity number, date of birth).
  • I can see these claims in the external cookie (IdentityConstants.ExternalScheme).
  • However, once ABP finalizes the login and issues tokens for the Angular app, these claims are gone.
  • I tried implementing IAbpClaimsPrincipalContributor to forward them, but the external cookie is not available for angular app (different domain/port).
  • Question: What is the proper ABP way to forward external provider claims (without persisting sensitive values like national identity number in the DB) so that they appear in the JWT used by the Angular client?
  1. Recognizing Authentication Type in API Calls
  • For security logic, I need to know if the current user authenticated via BankID or the standard username/password login.
  • In Swagger tests, I can inject and see custom claims, but once Angular is used, claims seem to be rewritten and the info is lost.
  • Question: What is the recommended approach in ABP to tag the authentication method (e.g., extenal (BankID) vs. local) so that this info reliably propagates into JWT tokens consumed by the Angular frontend?

Notes: I don’t want to persist national identity number in the database, so I’m looking for a runtime claim-forwarding approach. I’ve already explored AbpUserClaimsPrincipalFactory and IAbpClaimsPrincipalContributor. Claims show up in Swagger tests but not from Angular.

Thanks!

Hello,

I've encountered another issue with entity extension regarding UI localization. Here's the code I'm working with: property.DisplayName = new FixedLocalizableString("Label:BirthDate"); The label translates correctly in the "Create" and "Edit" forms, but it doesn't translate in the table headers. When I add :: before the localization key, the label is correctly translated in the table headers, but the "Create/Edit" forms show an empty string instead.

Could you please assist with resolving this?

Thanks. Any ideas when it can be fixed?

It didn't work. I believe the issue is not related to the EF type, as the migration already has the correct SQL type. It seems to be caused by a deserialization or mapping step in the pipeline. Since extra property values are stored as Object, it could be a boxing issue. When replacing IdentityUserAppService, I noticed that the BirthDate property is stored as DateTime instead of DateOnly. Additionally, the response includes a time part, which suggests unintended type conversion. Request:

{
 "extraProperties": {
   "NationalIdentityNumber": "12345678901",
   "BirthDate": "2001-03-27" <--- no time
 },
 "userName": "test",
 "name": "test",
 "surname": "test",
 "password": "test123",
 "email": "test@test",
 "phoneNumber": "",
 "isActive": true,
 "lockoutEnabled": true,
 "emailConfirmed": false,
 "phoneNumberConfirmed": false,
 "shouldChangePasswordOnNextLogin": false,
 "roleNames": [],
 "organizationUnitIds": []
}

Response:

{
    "tenantId": null,
    "userName": "test",
    "email": "test@test",
    "name": "test",
    "surname": "test",
    "emailConfirmed": false,
    "phoneNumber": "",
    "phoneNumberConfirmed": false,
    "supportTwoFactor": false,
    "twoFactorEnabled": false,
    "isActive": true,
    "lockoutEnabled": true,
    "isLockedOut": false,
    "lockoutEnd": null,
    "shouldChangePasswordOnNextLogin": false,
    "concurrencyStamp": "6d0c02c007114cfa8a6eb816bd9f277c",
    "roleNames": null,
    "accessFailedCount": 0,
    "lastPasswordChangeTime": "2025-03-27T07:16:52.8335677+00:00",
    "isExternal": false,
    "isDeleted": false,
    "deleterId": null,
    "deletionTime": null,
    "lastModificationTime": null,
    "lastModifierId": null,
    "creationTime": "2025-03-27T09:16:52.8579278+02:00",
    "creatorId": "519c6b51-3e6f-8cb8-cade-3a17de0dafb7",
    "id": "51e457a2-1a1e-5930-a2d4-3a18e8a2d980",
    "extraProperties": {
        "BirthDate": "2001-03-27T00:00:00", <---- time added
        "NationalIdentityNumber": "12345678901"
    }
}

This is how I see the problem:

  1. Incorrect type casting in the pipeline.
  2. The date is not saved in the database due to the wrong type, but no error is thrown; instead, a default value is set.
  3. The response includes the user’s input, but time is added to date.

Btw, on UI date input is a simple text input, not a date picker.

Hi! I need to add a couple of extra properties to the IdentityUser. One of these properties will represent the date of birth, and I would like its type to be DateOnly.


Below is my current code: EfCoreEntityExtensionMappings

            ObjectExtensionManager.Instance.MapEfCoreProperty<IdentityUser, string>(
                UserExtraPropertyNames.NationalIdentityNumber,
                (_, propertyBuilder) =>
                {
                    propertyBuilder.IsRequired();
                    propertyBuilder.HasColumnType("varchar(11)");
                });

            ObjectExtensionManager.Instance.MapEfCoreProperty<IdentityUser, DateOnly>(
                UserExtraPropertyNames.BirthDate,
                (_, propertyBuilder) =>
                {
                    propertyBuilder.IsRequired();
                });

ExtensionConfigurator

ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity =>
        {
            identity.ConfigureUser(user =>
            {
                user.AddOrUpdateProperty<string>(UserExtraPropertyNames.NationalIdentityNumber, property =>
                {
                    property.Attributes.Add(new RequiredAttribute());
                    property.Attributes.Add(new StringLengthAttribute(11) { MinimumLength = 11 });
                });
                
                user.AddOrUpdateProperty<DateOnly>(UserExtraPropertyNames.BirthDate, property =>
                {
                    property.DefaultValueFactory = () => DateOnly.FromDateTime(DateTime.Today);
                    
                    property.Validators.Add(context =>
                    {
                        
                    });
                });
            });
        });


The BirthDate property is never set and always has the default value of 0001-01-01 when a new user is created. I believe the issue is related to type casting. The BirthDate property has a DateTime type instead of DateOnly, which might be causing the problem.

Do you have any suggestions on how I can fix this?

Thanks!

Showing 21 to 30 of 43 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 December 17, 2025, 07:08
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.