I\'m trying to use the new MVC5 framework in VS 2013 preview.
The membership authentication framework has been overhauled and replaced with OWin
.
Using Alex Wheat's answer, I came up with a solution to retrive the google+ profile, gender and e-mail using Google Authentication.
Startup.Auth.cs:
var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
ClientId = "<<client id - google>>",
ClientSecret = "<<secret for your app>>",
Provider = new GoogleOAuth2AuthenticationProvider()
{
OnAuthenticated = context =>
{
var userDetail = context.User;
context.Identity.AddClaim(new Claim(ClaimTypes.Name,context.Identity.FindFirstValue(ClaimTypes.Name)));
context.Identity.AddClaim(new Claim(ClaimTypes.Email,context.Identity.FindFirstValue(ClaimTypes.Email)));
var gender = userDetail.Value<string>("gender");
context.Identity.AddClaim(new Claim(ClaimTypes.Gender, gender));
var picture = userDetail.Value<string>("picture");
context.Identity.AddClaim(new Claim("picture", picture));
return Task.FromResult(0);
},
},
};
googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
googleOptions.Scope.Add("https://www.googleapis.com/auth/userinfo.email");
app.UseGoogleAuthentication(googleOptions);
To get access to extended profile data, you should add two scopes to the request - plus.login and userinfo.email. If you only add the plus.login scope, you won't be able to see the user's e-mail. If you use ASP.NET MVC5's default template to authenticate, it will only show the user's e-mail, Name, Surname and google+ profile address. Using the way shown here, you'll have access also to the user's picture link.
The context.User property carries a JSON serialization of the user's data sent across the wire and have useful methods to let the user find a property by its key.
To learn more about login scopes concept, please take a look at: https://developers.google.com/+/api/oauth#login-scopes
The following works for me for facebook:
StartupAuth.cs:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "x",
AppSecret = "y"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
ExternalLoginCallback method:
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
And for Google:
StartupAuth.cs
app.UseGoogleAuthentication();
ExternalLoginCallback method (same as for facebook):
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
If I set a breakpoint here:
var email = emailClaim.Value;
I see the email address for both facebook and Google in the debugger.
Update: See this post instead for proper and complete solution; Getting the email from external providers Google and Facebook during account association step in a default MVC5 app
The following post details on how you can get extra data from the social providers http://blogs.msdn.com/b/webdev/archive/2013/10/16/get-more-information-from-social-providers-used-in-the-vs-2013-project-templates.aspx
So unfortunately this is not super straightforward, one way you can do this is to hook the GoogleProvider Authenticated event and add a custom claim to the Claims Identity with the avatar:
public class MyGoogleProvider : GoogleAuthenticationProvider {
public override Task Authenticated(GoogleAuthenticatedContext context) {
context.Identity.AddClaim(new Claim("avatarClaim", "<fetch avatar url here>"));
return base.Authenticated(context);
}
}
app.UseGoogleAuthentication(new GoogleAuthenticationOptions() { Provider = new MyGoogleProvider() });
Then inside of your AccountController, when the external identity is extracted, you can take this avatar claim and store it into your user object for use later.
Here is a good answer from AndrewPolland. Work for me. He use the new oauth access token to retrieve the user info after login. From here Deepak Goswami explain how to use this api call.
Recently I had to get access to Google profile's picture as well and here is how I solve it...
If you just enable the code app.UseGoogleAuthentication();
in the Startup.Auth.cs file it's not enough because in this case Google doesn't return any information about profile's picture at all (or I didn't figure out how to get it).
What you really need is using OAuth2 integration instead of Open ID that enabled by default. And here is how I did it...
First of all you have to register your app on Google side and get "Client ID" and "Client secret". As soon as this done you can go further (you will need it later). Detailed information how to do this here.
Replace app.UseGoogleAuthentication();
with
var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "<<CLIENT ID FROM GOOGLE>>",
ClientSecret = "<<CLIENT SECRET FROM GOOGLE>>",
CallbackPath = new PathString("/Account/ExternalGoogleLoginCallback"),
Provider = new GoogleOAuth2AuthenticationProvider() {
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new Claim("picture", context.User.GetValue("picture").ToString()));
context.Identity.AddClaim(new Claim("profile", context.User.GetValue("profile").ToString()));
}
}
};
googleOAuth2AuthenticationOptions.Scope.Add("email");
app.UseGoogleAuthentication(googleOAuth2AuthenticationOptions);
After that you can use the code to get access to the profile's picture URL same way as for any other properties
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var pictureClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type.Equals("picture"));
var pictureUrl = pictureClaim.Value;