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

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11