I'm new to using Identity Server for SPA auth but I started following this example: Authentication and authorization for SPAs and with some tinkering I've now also added Google auth. However, I'm having trouble getting the external Google claims merged into my application's claims (for example: given_name).
I've verified that Google does send back the appropriate claims but nothing seems to map those claims, e.g. options.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");. When I access one of my protected endpoints my claims do not include any of the additional google claims.
I did find some additional documentation Persist additional claims... which tells me to add the claim in OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) but since this is an SPA that page doesn't exist. Is there another approach to this? I haven't been able to find much that doesn't use the Page / OnPostConfirmationAsync.
Thanks
Including relevant details from my Startup.cs in case I'm doing something wrong here:
I've tried a few different variants from other examples I've found but
services
.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<AppRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer()
.AddApiAuthorization<AppUser, ApplicationDbContext>();
services
.AddAuthentication()
.AddIdentityServerJwt()
.AddGoogle(options =>
{
options.ClientId = Configuration["Auth:Google:ClientId"];
options.ClientSecret = Configuration["Auth:Google:ClientSecret"];
options.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response
options.AccessType = "offline";
options.SaveTokens = true;
options.Scope.Add("https://www.googleapis.com/auth/userinfo.email");
options.Scope.Add("https://www.googleapis.com/auth/userinfo.profile");
options.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
})
And my api is simply:
[Authorize()]
[Route("test")]
public IActionResult Test()
{
var all = User.Claims.Select(s => $"{s.Type}: {s.Value}");
return Ok(all);
}