Unauthorised webapi call returning login page rather than 401

Tim picture Tim · Nov 22, 2013 · Viewed 90.9k times · Source

How do I configure my mvc/webapi project so that a webapi method called from a razor view doesn't return the loginpage when its unauthorised?

Its a MVC5 application which also has WebApi controllers for calls via javascript.

The two methods below

[Route("api/home/LatestProblems")]      
[HttpGet()]
public List<vmLatestProblems> LatestProblems()
{
    // Something here
}

[Route("api/home/myLatestProblems")]
[HttpGet()]
[Authorize(Roles = "Member")]
public List<vmLatestProblems> mylatestproblems()
{
   // Something there
}

are called via the following angular code:

angular.module('appWorship').controller('latest', 
    ['$scope', '$http', function ($scope,$http) {         
        var urlBase = baseurl + '/api/home/LatestProblems';
        $http.get(urlBase).success(function (data) {
            $scope.data = data;
        }).error(function (data) {
            console.log(data);
        });
        $http.get(baseurl + '/api/home/mylatestproblems')
          .success(function (data) {
            $scope.data2 = data;
        }).error(function (data) {
            console.log(data);
        });  
    }]
);

So I'm not logged in and the first method successfully returns data. the second method returns (in the success function) data which contains the equivalent of a login page. i.e. what you would get in mvc if you requested a controller action which was stamped with [Authorize] and you weren't logged in.

I want it to return a 401 unauthorized, so that i can display different data for users based on if they are logged in or not. Ideally if the user is logged in i want to be able to access the Controller's User property so i can return data specific to that Member.

UPDATE: Since none of the suggestions below seem to work anymore (changes to Identity or WebAPI) ive created a raw example on github which should illustrate the problem.

Answer

Olav Nyb&#248; picture Olav Nybø · Nov 22, 2013

Brock Allen has a nice blog post on how to return 401 for ajax calls when using Cookie authentication and OWIN. http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/

Put this in ConfigureAuth method in the Startup.Auth.cs file:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
  AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
  LoginPath = new PathString("/Account/Login"),
  Provider = new CookieAuthenticationProvider
  {
    OnApplyRedirect = ctx =>
    {
      if (!IsAjaxRequest(ctx.Request))
      {
        ctx.Response.Redirect(ctx.RedirectUri);
      }
    }
  }
});

private static bool IsAjaxRequest(IOwinRequest request)
{
  IReadableStringCollection query = request.Query;
  if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest"))
  {
     return true;
  }
  IHeaderDictionary headers = request.Headers;
  return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest"));
}