Google Only authentication with ASP.net Identity

G

Recently I was working on a project where by I needed to authenticate out users against their Google apps login.

That is to say, the on authentication method would be Google. And only ever Google.
If they were signed in to their Google account, they would be signed into our app.

Most of the examples I found offered Google as an additional or supplementary authentication mechanism.
I wanted it to be the only mechanism to authenticate with our application.

Also, I wanted the users to have ‘roles’ within our application – for example ‘Admin’, ‘CustomerService’ etc…

So, to summarise the requirements:

  • Users will only sign in to our application with their Google Account.
  • They will not have a username / password
  • Once signed in, if they had an account with our application (using ASP.net Identity) authenticate, and continue as normal.
    • If not, create an account (in the sense of ASP.net Identity), then authenticate the user, and continue to our application

For this to work, you’ll need a Google application to authenticate against.

I wrote a short separate post about how to do that here:
http://www.alexjamesbrown.com/blog/development/create-a-google-application-for-authenticating-against-with-asp-net-identity/

Take special note of the Google+ API requirement, and ensure your redirect URL is set appropriately to http://localhost:<port>/signin-google if testing locally

You’ll then need to configure your authentication to use the credentials provided by the above:

app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    ClientId = “xxx.apps.googleusercontent.com",
    ClientSecret = “xxxxxxxxxxxx",
});

Most of the code in my example follows on from the usual tutorials on the subject of ASP.net Identity with Google –

We have a  ExternalLoginCallback method in our AuthenticationController,  which is called by Google when authenticated.

In here, we retrieve the user information. We then check if a user exists in our database.
If it does, using our  SignInManager, we sign the user in, and proceed.
If we don’t have a user, we create one, with the information we have about the successful login with the third party (in this case, Google)

Apparently, if you don’t want to have the endpoint of /signin-google as shown in the post, you can change >the redirect url value in GoogleOAuth2AuthenticationOptions:

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
   //clientid client secret goes here
   CallbackPath = “<path>” //put your path here
}

Inside our AuthenticationController is where the real magic happens

I’ve commented what’s going on below;

[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();

//One potentially useful thing we could do here is throw a 403 if the authenticated user
//is not part of our corporate domain
//if(!loginInfo.Email.EndsWith("@mydomain.com")
//    throw new HttpUnauthorizedResult();

//See if the user exists in our database
var user = await UserManager.FindByEmailAsync(loginInfo.Email);

if (user == null)
{
    //user doesn't exist, so the user needs to be created
    user = new ApplicationUser
    {
        UserName = loginInfo.Email,
        Email = loginInfo.Email,
        EmailConfirmed = true,
        FirstName = loginInfo.ExternalIdentity.Claims.FirstOrDefault(x => x.Type.Equals(ClaimTypes.GivenName)).Value,
        LastName = loginInfo.ExternalIdentity.Claims.FirstOrDefault(x => x.Type.Equals(ClaimTypes.Surname)).Value
    };

    //create the user
    await UserManager.CreateAsync(user);
    //add the google login to the newly created user
    await UserManager.AddLoginAsync(user.Id, loginInfo.Login);
    //add user to roles if required here....
}

//if user logins doesn't contain Google, then add it
if (!user.Logins.Any(x => x.LoginProvider.Equals("Google")))
    await UserManager.AddLoginAsync(user.Id, loginInfo.Login);

//successfully authenticated with google, so sign them in to our app
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

return RedirectToLocal(returnUrl);
}

For a full working example, please checkout:
https://github.com/alexjamesbrown/aspnet-google-only-authentication