Open Closed

OAuth External Login Problem between two different ABP Projects #3866


User avatar
0
yavuz.ozbek created
  • ABP Framework version: v6.0.0
  • UI type: Angular / MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no

I have two different abp projects. One is MVC, other is Angular. (Client is Angular oauth server is MVC project) i have created a new Application and scope to OpenIdDict in MVC Project. In Angular project I have opened Oauth external login in settings and entered that information to Angular project like this link . I have created a test username to both projects, when i run two projects and enter user-password in angular project gives error "Exception: Unable to get the email of external user!". How can i solve the problem? Thanks.

  • Exception message and stack trace:
    Exception: Unable to get the email of external user! Volo.Abp.Identity.ExternalLoginProviders.OAuth.OAuthExternalLoginProvider.MapClaimsToExternalLoginUserInfoAsync(IEnumerable<Claim> claims) Volo.Abp.Identity.ExternalLoginProviders.OAuth.OAuthExternalLoginProvider.GetUserInfoAsync(string userName, string plainPassword) Volo.Abp.Identity.ExternalLoginProviderWithPasswordBase.UpdateUserAsync(IdentityUser user, string providerName, string plainPassword) Volo.Abp.Identity.AspNetCore.AbpSignInManager.PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure) Volo.Abp.Account.Public.Web.Pages.Account.LoginModel.OnPostAsync(string action) Volo.Abp.Account.Web.Pages.Account.OpenIddictSupportedLoginModel.OnPostAsync(string action) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Convert<T>(object taskAsObject) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Execute(object receiver, object[] arguments) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync() Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync() Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) Volo.Abp.AspNetCore.Serilog.AbpSerilogMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) Volo.Abp.AspNetCore.Uow.AbpUnitOfWorkMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Volo.Abp.AspNetCore.MultiTenancy.MultiTenancyMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Microsoft.AspNetCore.Builder.ApplicationBuilderAbpOpenIddictMiddlewareExtension+<>c__DisplayClass0_0+<<UseAbpOpenIddictValidation>b__0>d.MoveNext() Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) Volo.Abp.AspNetCore.Security.AbpSecurityHeadersMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext() Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)


13 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Unable to get the email of external user!

    Try to debug the MapClaimsToExternalLoginUserInfoAsync method. share the values of claims

    Configure<AbpIdentityOptions>(options =>
    {
        options.ExternalLoginProviders.RemoveAll(x => x.Key == "OAuth");
        options.ExternalLoginProviders.Add<MyOAuthExternalLoginProvider>(MyOAuthExternalLoginProvider.Name);
    });
    
    
    public class MyOAuthExternalLoginProvider : OAuthExternalLoginProvider
    {
        public const string Name = "OAuth";
    
        public ILogger<OAuthExternalLoginProvider> Logger { get; set; }
    
        protected OAuthExternalLoginManager OAuthExternalLoginManager { get; }
    
        protected ISettingProvider SettingProvider { get; }
    
        protected IFeatureChecker FeatureChecker { get; }
    
        protected AbpOAuthExternalLoginProviderOptions Options { get; }
    
    
        public MyOAuthExternalLoginProvider(
            IGuidGenerator guidGenerator,
            ICurrentTenant currentTenant,
            IdentityUserManager userManager,
            IIdentityUserRepository identityUserRepository,
            IOptions<IdentityOptions> identityOptions,
            OAuthExternalLoginManager oAuthExternalLoginManager,
            ISettingProvider settingProvider,
            IFeatureChecker featureChecker,
            IOptions<AbpOAuthExternalLoginProviderOptions> options)
            : base(guidGenerator, currentTenant, userManager, identityUserRepository, identityOptions, oAuthExternalLoginManager, settingProvider, featureChecker, options)
        {
        }
    
        protected override Task<ExternalLoginUserInfo> MapClaimsToExternalLoginUserInfoAsync(IEnumerable<Claim> claims)
        {
            var claimsArray = claims as Claim[] ?? claims.ToArray();
    
            var email = claimsArray.FirstOrDefault(x => x.Type == Options.EmailClaimType);
            if(email == null)
            {
                throw new Exception("Unable to get the email of external user!");
            }
    
            var userInfo = new ExternalLoginUserInfo(email.Value)
            {
                Name = claimsArray.FirstOrDefault(x => x.Type == Options.NameClaimType)?.Value,
                Surname = claimsArray.FirstOrDefault(x => x.Type == Options.SurnameClaimType)?.Value,
                EmailConfirmed = claimsArray.FirstOrDefault(x => x.Type == Options.EmailConfirmedClaimType)?.Value.To<bool>() ?? false,
                PhoneNumber = claimsArray.FirstOrDefault(x => x.Type == Options.PhoneNumberClaimType)?.Value,
                PhoneNumberConfirmed = claimsArray.FirstOrDefault(x => x.Type == Options.PhoneNumberConfirmedClaimType)?.Value.To<bool>() ?? false,
                ProviderKey = claimsArray.FirstOrDefault(x => x.Type == Options.ProviderKeyClaimType)?.Value
            };
    
            return Task.FromResult(userInfo);
        }
    
    }
    
  • User Avatar
    0
    yavuz.ozbek created

    Here is the debug value of claims:

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    It seems your oauth server does not return the required claims.

  • User Avatar
    0
    yavuz.ozbek created

    My OAuth server is an application that is an mvc application created from abp suite. I add Angular app's informations to open id dict which i add the picture to first message. So how can i add required claims to oauth (Web app that was created from suite) server ?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you share a minimum project with me?

  • User Avatar
    0
    yavuz.ozbek created

    Hi,

    I have created starter ASP.Net MVC project via suite and share with you on github.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    What are the steps to reproduce the problem on your shared project?

  • User Avatar
    0
    yavuz.ozbek created

    It's not as complicated as you think. I have different two ABP Projects. One is MVC other is Angular based.

    1. I created new Asp.Net MVC project from abp suite (OAuth server)
    2. I created another new Angular based abp project from abp suite. (Different client project )
    3. In the above first message i added a picture that's name is Openiddict Application Configuration (In mvc project add a new configuration for other abp angular client )
    4. In the above first message i added a picture that's name is Angular Project Client (In angular project add fill the OAuth Login Setting)

    I did not do any extra action other than what I wrote above. Then when i login in Angular project it authenticates from OAuth server bu gets Exception: Unable to get the email of external user! namely my oauth server does not return the required claims.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Can you provide these two projects(MVC & angular)? I hope I can reproduce the problem locally and then fix it.

  • User Avatar
    0
    yavuz.ozbek created

    I shared two projects with you in github

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Thanks, I will check it asap

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Use Angular profile email address roles as Scope.

  • User Avatar
    0
    yavuz.ozbek created

    Hi,

    Thanks. I add these scopes to both client and server apps then it gets email address and login is successfull

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 v9.3.0-preview. Updated on May 15, 2025, 10:28