If user is authenticated via google, I need to get his profile picture.
If user is authenticated via facebook I get his profile picture with this code:
var info = await _signInManager.GetExternalLoginInfoAsync();
var identifier = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var picture = $"https://graph.facebook.com/{identifier}/picture"; // 3
So, which code I need to use in 3 line for getting user's profile picture in case user is authenticated via google?
Accessing user profile picture, full solution.
Stack:
Asp Net Identity 4 v4 + Asp Net Identity + Google People Api
1.1 I'm using default HttpClient to generate HTTP requests to Google API
1.2 Install NUGET System.Net.Http.Json to ease serialization.
1.3 Use a [json to c#] tool, to create a DTO like this:
/// <summary>
/// 🟡 official docs.
/// https://developers.google.com/people/api/rest/v1/people#Person.Photo
/// </summary>
public class PeopleApiPhotos {
public string resourceName { get; set; }
public string etag { get; set; }
public List<Photo> photos { get; set; }
public class Source {
public string type { get; set; }
public string id { get; set; }
}
public class Metadata {
public bool primary { get; set; }
public Source source { get; set; }
}
public class Photo {
public Metadata metadata { get; set; }
public string url { get; set; }
}
}
Identity Server with Asp Net Identity > Login > OnPostConfirmationAsync: FULL METHOD
public async Task < IActionResult > OnPostConfirmationAsync(string returnUrl = null) {
returnUrl = returnUrl ? ?Url.Content("~/");
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null) {
ErrorMessage = "Error loading external login information during confirmation.";
return RedirectToPage("./Login", new {
ReturnUrl = returnUrl
});
}
// try to get profile picture
string pictureUri = string.Empty;
if (info.LoginProvider.ToLower() == "google") {
var httpClient = _httpClientFactory.CreateClient();
string peopleApiKey = _configuration["GoogleApiKey:PeopleApiKey"];;
var googleAccountId = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var photosResponse = await httpClient.GetFromJsonAsync < PeopleApiPhotos > (
$ "https://people.googleapis.com/v1/people/{googleAccountId}?personFields=photos&key={peopleApiKey}");
pictureUri = photosResponse ? .photos.FirstOrDefault() ? .url;
}
if (ModelState.IsValid) {
// Cria usuário
var user = new AppUser {
UserName = Input.Email,
Email = Input.Email,
FirstName = Input.FirstName,
LastName = Input.LastName,
ProfilePictureUrl = pictureUri
};
var result = await _userManager.CreateAsync(user);
if (result.Succeeded) {
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded) {
_logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page("/Account/ConfirmEmail", pageHandler: null, values: new {
area = "Identity",
userId = userId,
code = code
},
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $ "Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
// If account confirmation is required, we need to show the link if we don't have a real email sender
if (_userManager.Options.SignIn.RequireConfirmedAccount) {
return RedirectToPage("./RegisterConfirmation", new {
Email = Input.Email
});
}
await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);
return LocalRedirect(returnUrl);
}
}
foreach(var error in result.Errors) {
ModelState.AddModelError(string.Empty, error.Description);
}
}
ProviderDisplayName = info.ProviderDisplayName;
ReturnUrl = returnUrl;
return Page();
}
❗️ this is only a little part from full method above.
Checks if external provider is Google, and use [NameIdentifier] and [Google Api Key] to reach People Endpoint.
// try to get profile picture
string pictureUri = string.Empty;
if (info.LoginProvider.ToLower() == "google") {
var httpClient = _httpClientFactory.CreateClient();
// ApiKey can get generated in [Google Developers Console](https://console.developers.google.com/apis/credentials).
string peopleApiKey = _configuration["GoogleApiKey:PeopleApiKey"];;
var googleAccountId = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var photosResponse = await httpClient.GetFromJsonAsync < PeopleApiPhotos > (
$ "https://people.googleapis.com/v1/people/{googleAccountId}?personFields=photos&key={peopleApiKey}");
pictureUri = photosResponse ? .photos.FirstOrDefault() ? .url;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context) {
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
claims.Add(new Claim(JwtClaimTypes.GivenName, user.FirstName));
claims.Add(new Claim(JwtClaimTypes.FamilyName, user.LastName));
// Insert a new claim, that gets ProfilePictureUrl persisted in my app user in database.
claims.Add(new Claim(JwtClaimTypes.Picture, user.ProfilePictureUrl));
context.IssuedClaims = claims;
}
To get user profile data in frontend, i'm using OidcClient-js
// here i'm using oidc-client.js
// user object is loaded with user full data.
let profilePictureUrl = user.profile.picture;
Thanks to @DaImTo response.