IdentityServer / IdentityServer4.Templates

dotnet new templates for IdentityServer4
Apache License 2.0
695 stars 229 forks source link

Not redirected to Spa client when using External authentication. Works when using username / pass. #85

Closed mdmoura closed 4 years ago

mdmoura commented 4 years ago

I am using the ASP.Net Core Identity Template with an Angular SPA client.

Starting the login process on the SPA I am redirected to Identity Server 4 login page.

  1. If I login with Username/Password I am redirected back to the login callback url of the SPA:

    AccountController > Login code that fires the redirect (return Redirect(model.ReturnUrl)):

    if (context != null) {
      if (context.IsNativeClient()) {
        // The client is native, so this change in how to
        // return the response is for better UX for the end user.
           return this.LoadingPage("Redirect", model.ReturnUrl);
      }
      // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
       return Redirect(model.ReturnUrl);
    }
  2. But if I login using Google's External authentication after I give the consent in Google I am redirected to Identity Server 4's Login page but I am never redirected to the SPA callback url:

    ExternalController > Callback code that fires the redirect (return Redirect(returnUrl)):

    if (context != null) {
      if (context.IsNativeClient()) {
        // The client is native, so this change in how to
        // return the response is for better UX for the end user.
          return this.LoadingPage("Redirect", returnUrl);
      }
    }
    return Redirect(returnUrl);

I checked the Model.ReturnUrl and returnUrl and they are similar:

/connect/authorize/callback?client_id=spa&redirect_uri=https%3A%2F%2Flocalhost%3A5002%2Fsignin&response_type=code&scope=openid%20profile%20email%20offline_access%20api&state=630f254e106f47db87f95851fec3a305&code_challenge=ZnQhChbz2TNnL_nH7RmZ5Agc7JEmb3uUcefXkD77oIo&code_challenge_method=S256&response_mode=query

/connect/authorize/callback?client_id=spa&redirect_uri=https%3A%2F%2Flocalhost%3A5002%2Fsignin&response_type=code&scope=openid%20profile%20email%20offline_access%20api&state=85c6da19dd2f45069dad51238ebb4779&code_challenge=yKZzJpq-PCNRfzY_-W3T8xNOTJL8fg65k0t8NZHbQVk&code_challenge_method=S256&response_mode=query

What am I missing?

mdmoura commented 4 years ago

@brockallen I found the problem and it happens when ProfileService is added:

services.AddScoped<IProfileService, ProfileService>(); 

With this I am not redirected do SPA client's login callback after external login even if the login is successful on IS.

I even tried with a very simple ProfileService:

  public class ProfileService : IProfileService {

    private readonly IUserClaimsPrincipalFactory<User> _claimsFactory;
    private readonly UserManager<User> _userManager;

    public ProfileService(UserManager<User> userManager, IUserClaimsPrincipalFactory<User> claimsFactory) {
      _userManager = userManager;
      _claimsFactory = claimsFactory;
    } 

    public async Task GetProfileDataAsync(ProfileDataRequestContext context) {
      User user = await _userManager.GetUserAsync(context.Subject);
      ClaimsPrincipal principal = await _claimsFactory.CreateAsync(user); 
      context.IssuedClaims = principal.Claims.ToList();
    }

    public async Task IsActiveAsync(IsActiveContext context) {
      User user = await _userManager.GetUserAsync(context.Subject);
      context.IsActive = (user != null) && user.Enabled;
    } 

  }

Am I missing something or is this a bug?

brockallen commented 4 years ago

I'd suggest you test with our pre-built samples. You should see that they work. Then compare those to yours.