Search code examples
c#angularauthenticationasp.net-coreasp.net-core-identity

ASP.NET Core Identify Auth + Angular: Login Not Working


I'm presently developing an application with an ASP.NET Core (2.1) API server/backend and an Angular Single Page Application frontend.

For user authentication, I'm using ASP.NET Core Identity, along with several of the default methods provided within AccountController for login, logout, register, forgot password, etc. My Angular application accesses this API to perform these actions.

The Angular client files are hosted directly out of wwwroot in the ASP.NET Core application. I am hosting using IIS Express (I have tried IIS as well to no avail) under localhost:5000.

Authentication is configured in ASP.NET Core's Startup class with the following:

services.AddIdentity<ApplicationUser, IdentityRole>(config =>
    {
        config.SignIn.RequireConfirmedEmail = false;
        config.Password.RequiredLength = 8;
    })
    .AddEntityFrameworkStores<AppDbContext>()
    .AddDefaultTokenProviders();

// Prevent API from redirecting to login or Access Denied screens (Angular handles these).
services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;
        return Task.CompletedTask;
    };
    options.Events.OnRedirectToAccessDenied = context =>
    {
        context.Response.StatusCode = 403;
        return Task.CompletedTask;
    };
});

Register and Forgot Password both work without a hitch. The API is called and the appropriate actions are taken.

Login appears to work: The method is invoked within Angular:

@Injectable()
export class AuthService extends BaseService {
  constructor(private httpClient: HttpClient) {
    super(httpClient, `${config.SERVER_API_URL}/account`);
  }

  // Snip

  login(login: Login): Observable<boolean> {
    return this.httpClient.post<boolean>(`${this.actionUrl}/Login`, login)
      .catch(this.handleError);
  }

  // Snip
}

The ASP.NET Core API gets the call, logs the user in, and returns success to indicate to Angular that login worked and they should proceed to redirect the user:

namespace ApartmentBonds.Web.Api.Account
{
    [Route("api/[controller]/[action]")]
    public class AccountController : APIControllerBase
    {
        // Snip

        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> Login([FromBody] LoginViewModel model, string returnUrl = null)
        {
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

            ViewData["ReturnUrl"] = returnUrl;
            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, false);
                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return Ok(true);
                }
            }

            return Ok(false);
        }

        // Snip
    }
}

The session cookie is created successfully, and I can see it within the browser (using Firefox Quantum in this screenshot, but have also tried in IE, in Firefox incognito, etc):

Cookie

To test, I have another API method which simply returns whether or not the calling user is signed in:

// Angular
isLoggedIn(): Observable<boolean> {
  return this.httpClient.get<boolean>(`${this.actionUrl}/IsLoggedIn`)
    .catch(this.handleError);
}

// ASP.NET Core API
[HttpGet]
[AllowAnonymous]
public IActionResult IsLoggedIn()
{
    return Ok(_signInManager.IsSignedIn(User));
}

I make this call within the browser, and it returns false. (All other aspects of the site that depend on the user being logged in also show the user is not logged in -- this method is just a quick and dirty way to verify this problem.) Note that the client is correctly sending the Identity cookie along with the request:

IsLoggedIn Request

Since the only site in question here is localhost:5000 I'm not sure why this is not working.

Things I've tried

  • Within services.ConfigureApplicationCookie
    • Setting options.Events.Cookie.Domain to localhost:5000 explicitly
    • Setting options.Events.Cookie.Path to /api
  • Clearing all cookies and trying incognito/other browsers (to rule out other localhost site cookies potentially clobbering the request)
  • Hosting the site via IIS (localhost:8888) after Publishing the Core Application

Anyone have any ideas?


Solution

  • In order for authentication handlers to run on the request, you need app.UseAuthentication(); in the middleware pipeline (before middleware that requires it like MVC).