ASP.NET WebApi FormsAuthentication 401 (Unauthorized) issue

Richard O'Neil picture Richard O'Neil · Oct 12, 2012 · Viewed 7.4k times · Source

I have been learning how authorization works in ASP.Net WebApi and I came across an answer by Darin Dimitrov in another posting ( ASP.NET Web API Authentication ) and I need some help understanding why I'm getting a 401.

Following Darin's code, I have created a WebApi project and added the following controllers and model:

AccountController.cs

using System.Web.Http;
using System.Web.Security;
using AuthTest.Models;

namespace AuthTest.Controllers
{
    public class AccountController : ApiController
    {
        public bool Post(LogOnModel model)
        {
            if (model.Username == "john" && model.Password == "secret")
            {
                FormsAuthentication.SetAuthCookie(model.Username, false);
                return true;
            }

            return false;
        }
    }
}

UsersController.cs

using System.Web.Http;

namespace AuthTest.Controllers
{
    [Authorize]
    public class UsersController : ApiController
    {
        public string Get()
        {
            return "This is top secret material that only authorized users can see";
        }
    }
}

LogOnModel.cs

namespace AuthTest.Models
{
    public class LogOnModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

I have created a Web Forms app with two buttons and a label for testing purposes.

Default.aspx.cs

using System;
using System.Net.Http;
using System.Threading;

namespace AuthTestWebForms
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void ButtonAuthorizeClick(object sender, EventArgs e)
        {
            using (var httpClient = new HttpClient())
            {
                var response = httpClient.PostAsJsonAsync(
                    "http://localhost/authtest/api/account",
                    new { username = "john", password = "secret" },
                    CancellationToken.None
                ).Result;
                response.EnsureSuccessStatusCode();

                bool success = response.Content.ReadAsAsync<bool>().Result;
                if (success)
                {
                    //LabelResponse.Text = @"Credentials provided";
                    var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
                    LabelResponse.Text = secret.Result;
                }
                else
                {
                    LabelResponse.Text = @"Sorry, you provided the wrong credentials";
                }
            }
        }

        protected void ButtonTestAuthClick(object sender, EventArgs e)
        {
            using (var httpClient = new HttpClient())
            {
                var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
                LabelResponse.Text = secret.Result;
            }
        }
    }
}

When I click the button and run ButtonAuthorizeClick() it fires the controller for Account and then fires the controller for Users and everything is fine.

If I then click the ButtonTestAuthClick(), I get a 401 (Unauthorized) error.

When I look for the ASPXAUTH cookie in Chrome or FireFox, I don't see one, so I'm not 100% sure why ButtonAuthorizeClick() works and what I need to do to make ButtonTestAuthClick() work.

Thanks for any help anybody can throw my way.

Answer

DrBoom picture DrBoom · Nov 2, 2012

I was having a similar problem, though not via a Web Forms client page but rather with JavaScript and AJAX calls. Turns out I had left the authentication mode in the web.config left at "None". Obviously, you have to turn on Forms Authentication here in order for the FormsAuthentication.SetAuthCookie() method to have any effect.

<authentication mode="Forms" />

Once I fixed this oversight, everything starting working fine. :-)