Question

I am trying to understand the new OWIN Bearer Token authentication process in the Single Page App template in MVC 5. Please correct me if I'm wrong, for the OAuth password client authentication flow, Bearer Token authentication works by checking the http authorization request header for the Bearer access token code to see if a request is authenticated, it doesn't rely on cookie to check if a particular request is authenticated.

According to this post:

OWIN Bearer Token Authentication with Web API Sample

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    using (IdentityManager identityManager = _identityManagerFactory.CreateStoreManager())
    {
        if (!await identityManager.Passwords.CheckPasswordAsync(context.UserName, context.Password))
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }

        string userId = await identityManager.Logins.GetUserIdForLocalLoginAsync(context.UserName);
        IEnumerable<Claim> claims = await GetClaimsAsync(identityManager, userId);
        ClaimsIdentity oAuthIdentity = CreateIdentity(identityManager, claims,
            context.Options.AuthenticationType);
        ClaimsIdentity cookiesIdentity = CreateIdentity(identityManager, claims,
            _cookieOptions.AuthenticationType);
        AuthenticationProperties properties = await CreatePropertiesAsync(identityManager, userId);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(cookiesIdentity);
    }
}

The GrantReourceOwnerCredentials function not only compose the ticket with this line: context.Validated(ticket); but it also compose a cookie identity and set it to the cookie with this line: context.Request.Context.Authentication.SignIn(cookiesIdentity);

So my questions are, what is the exact purpose of the cookie in this function? Shouldn't the AuthenticationTicket be good enough for authentication purpose?

Was it helpful?

Solution

In the SPA template there are actually two separate authentication mechanisms enabled- cookie authentication and token authentication. This enables authentication of both MVC and Web API controller actions, but requires some additional setup.

If you look in the WebApiConfig.Register method you'll see this line of code:

    config.SuppressDefaultHostAuthentication();

That tells Web API to ignore cookie authentication, which avoids a host of problems which are explained in the link you posted in your question:

"...the SPA template enables application cookie middleware as active mode as well in order to enable other scenarios like MVC authentication. So Web API will still be authenticated if the request has session cookie but without a bearer token. That’s probably not what you want as you would be venerable to CSRF attacks for your APIs. Another negative impact is that if request is unauthorized, both middleware components will apply challenges to it. The cookie middleware will alter the 401 response to a 302 to redirect to the login page. That is also not what you want in a Web API request."

So now with the call to config.SuppressDefaultHostAuthentication() Web API calls that require authorization will ignore the cookie that is automatically sent along with the request and look for an Authorization header that begins with "Bearer". MVC controllers will continue to use cookie authentication and are ignorant of the token authentication mechanism as it's not a very good fit for web page authentication to begin with.

OTHER TIPS

The existence of the cookie also left me puzzled, since it clearly is not necessary in a bearer token authentication scenario... In this post the author dissects the individual accounts template, and has the following to say about the cookie:

The method also sets an application cookie. I don’t see a good reason for that.

My guess is that the authors of the template wanted to show examples of different kinds of authentication logic, and in this particular case they wanted to show how the authentication information could be stored in both the bearer token authentication JSON payload, as well as in a standard authentication cookie.

The fact that the JSON authentication payload is set to also include an additional (unnecessary) unencrypted property (the user id), in addition to the encrypted ticket, seems to support this theory:

var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);

It seems that the authors of the template wanted to provide some useful examples, rather than the bare minimum needed to achieve bearer token authentication. This is also mentioned in the linked post above.

The cookie has one important purpose. Its value contains the bearer token which can be extracted by client-side javascript on your pages. This means that if the user hits F5 or refreshes the page, the cookie will typically persist. Your client-side javascript can then grab the bearer token from the cookie when the page reloads.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top