36

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?

Ahmed Mansour
  • 527
  • 5
  • 13
gavin
  • 1,276
  • 1
  • 11
  • 17
  • Link of post your are referring to has changed, now it is https://blogs.msdn.microsoft.com/webdev/2013/09/20/understanding-security-features-in-the-spa-template-for-vs2013-rc/ – Himalaya Garg Dec 02 '16 at 03:57

3 Answers3

37

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.

Ahmed Mansour
  • 527
  • 5
  • 13
joelmdev
  • 11,083
  • 10
  • 65
  • 89
  • 2
    To add to this, there is an field in CookieAuthenticationOptions called CookieHttpOnly. If you set this to true, the browser won't send the cookie with the JavaScript generated API request at all, saving you some bandwidth and potential confusion when debugging. – ThisGuy Aug 12 '14 at 00:06
  • What you mean by "MVC controllers will continue to use cookie authentication..." ? With this line of code config.SuppressDefaultHostAuthentication() i'm able to use cookies authentication in MVC apps and Bearer Token authentication in Mobile Apps ? – mmarques Oct 28 '14 at 23:03
  • @mmarques I think you answered your own question. MVC will use cookie authentication and Web API will use bearer token authentication as configured above. – joelmdev Oct 31 '14 at 16:19
  • 1
    @ThisGuy The default is true anyway, though kudos for mentioning it. – GFoley83 Nov 25 '14 at 19:32
  • @joelmdev, why do you think that token authentication mechanism it is not a very good fit for web? – Pepito Fernandez Dec 13 '14 at 19:46
  • 1
    @Tony because you have to manually add the bearer token header on every request. A plan old anchor tag to take you to an authenticated page wouldn't work. Cookies for a domain are sent along with the request automatically. – joelmdev Dec 13 '14 at 21:40
3

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.

adner1
  • 186
  • 6
  • 3
    That author (http://stackoverflow.com/users/672453/leastprivilege) also happens to know just a smidgen about the topic. He's the author of Thinktecture.IdentityServer and this MS paper on Claims-Based Identity (http://msdn.microsoft.com/en-us/library/ff423674.aspx) – EBarr Feb 12 '14 at 01:18
-1

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.

Nobby
  • 1