Reputation: 1725
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);
}
Upvotes: 2
Views: 1463
Reputation: 1725
The only way I've been able to handle this is to scaffold the needed ExternalLogin page (like @d_f mentioned in the question's comments) and then continue following the Persist additional claims steps. I was hoping I could just set a collection of claims to keep in my Startup file and it would work but Identity Server just uses its internal ExternalLogin
(Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal) and the code there doesn't handle adding external claims. This works for now but I would prefer a way of not needing to scaffold the ExternalLogin page.
I tried asking for clarification on the official docs but my question was closed (instead they suggested I ask on StackOverflow - lol). However there seems to be some work being done on improving the docs and flowing the claims through, if interested you can dig through this GitHub issue: https://github.com/dotnet/AspNetCore.Docs/issues/16488
Upvotes: 2