Barebones ASP.NET MVC Google Signin through OWIN Middleware

If you use Visual Studio and want to add Google sign-in to your ASP.NET MVC app by using an out of box template, you get code that uses ASP.NET identity and three Katana authentication middleware: (1) the cookie authentication middleware running in active mode, (2) another instance of cookie authentication middleware but running in passive mode, and (3) Google authentication middleware. That will be like so.

app.UseCookieAuthentication(...); // Active
app.UseExternalSignInCookie(...); // Passive
app.UseGoogleAuthentication(...);

However, if you do not want to use ASP.NET identity for any reason and if you do not want to use any application specific claims, you don’t need to use the cookie authentication middleware running in active mode and there will be no call back as well – the version I’d like to call as bare bones Google sign-in.

Here is the ASP.NET empty project (MVC ticked) with NuGet references to Microsoft.Owin.Host.SystemWeb, Microsoft.Owin.Security.Cookies, and Microsoft.Owin.Security.Google. My startup is like so.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(
                                      "GoogleCookie");
        app.UseCookieAuthentication(
                        new CookieAuthenticationOptions
        {
            AuthenticationType = "GoogleCookie"
        });

        app.UseGoogleAuthentication(
                new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = "<ClientId>",
            ClientSecret = "<ClientSecret>"
        });
    }
}

I have a cookie middleware running in active mode (default) and the Google authentication middleware. I do not signoff and delete the cookie granted by Google middleware. I just use it in all subsequent requests and use the cookie middleware to read this cookie and establish identity.

My Controller is like so.

[GoogleAuthorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

public class GoogleAuthorizeAttribute
                         : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(
                   AuthorizationContext filterContext)
    {
        filterContext.HttpContext
            .GetOwinContext().Authentication
                .Challenge("Google");
    }
}

I’m using a custom authorization filter to call the Google middleware on 401. There is no callback and after successful authentication, you get redirected to the home page and the cookie middleware establishes identity. If you have a view for your home page like so, you will see the claims part of the identity.

@{
    ViewBag.Title = "Home";
}

<h2>Home, sweet home. Welcome, @User.Identity.Name</h2>

@{
    var identity = User.Identity as 
               System.Security.Claims.ClaimsIdentity;
}

@if (identity != null)
{
    <table>
        @foreach (var claim in identity.Claims)
        {
            <tr>
                <td>@claim.Type</td>
                <td>@claim.Value</td>
            </tr>
        }
    </table>
}

So, this post is just to illustrate two cookie middleware components are not mandatory. It just makes the life easier, if you have application specific claims, which most of the applications will. With what we have so far, no application specific claims are used but then it is possible to use a database to retrieve claims on every request, if that is what you want and you can use an OWIN middleware like so.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(
                                      "GoogleCookie");
        app.UseCookieAuthentication(
                        new CookieAuthenticationOptions
        {
            AuthenticationType = "GoogleCookie"
        });

        // Application-specific claims are added here
        app.Use((IOwinContext c, Func<Task> next) =>
        {
            var identity = c.Authentication
                .User.Identity as ClaimsIdentity;
            if (identity != null && 
                     identity.IsAuthenticated)
                identity.AddClaim(
                      new Claim(ClaimTypes.Role,
                                       "admin"));

            return next.Invoke();
        });

        app.UseGoogleAuthentication(
                new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = "<ClientId>",
            ClientSecret = "<ClientSecret>"
        });
    }
}

PS. Inspiration for this blog post is derived from the SO question http://stackoverflow.com/questions/26166826/usecookieauthentication-vs-useexternalsignincookie. The code in this post are simplified to the maximum extent and hence not production strength.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s