Hello, I’m quite new to OIDC in general, so apologies in advance if this is a stupid question.
I’m following the quickstart guides:
- https://auth0.com/docs/quickstart/webapp/aspnet-core-3/01-login
- Auth0 ASP.NET Core Web API SDK Quickstarts: Authorization
- https://github.com/auth0-samples/auth0-aspnetcore-webapi-samples/tree/master/Samples/user-info
Everything is working as expected:
- When I browse to an [Authorize] route in MVC, I get redirected to Auth0 login. I get back an id_token and access_token after logging in.
- I can use the access_token to access [Authorize] endpoints in the API.
Question: Is it possible to force additional claims into the access_token? If yes, how do I do this?
For context, this is an example of the decoded access_token:
{
“alg”: “RS256”,
“typ”: “JWT”,
“kid”: “Oh3auIcHF7FKoi_maBqKe”
}.{
“iss”: “https://blah.au.auth0.com/”,
“sub”: “auth0|5ebb0ff83873a20be682a54b”,
“aud”: [
“https://api.blah.net”,
“https://blah.au.auth0.com/userinfo”
],
“iat”: 1589924568,
“exp”: 1590010968,
“azp”: “2wDvZX5y1vXRj70U37hIzezV2IPDqgbt”,
“scope”: “openid profile email read:messages”
}.[Signature]
The reason for this is that in my current environment, existing user data is typically stored with email address as the primary key. When the API endpoints are called, it needs to access the user’s data using their email address.
From all the reading I’ve done so far, the typical answer is to call the /userinfo endpoint to obtain additional information about a user.
So I could get that information by doing a POST to https://blah.au.auth0.com/userinfo
using the access token.
Something like the code below:
Microsoft.Extensions.Primitives.StringValues authTokens;
HttpContext.Request.Headers.TryGetValue("Authorization", out authTokens);
var accessToken = authTokens.FirstOrDefault();
var request = new HttpRequestMessage(HttpMethod.Get,
"https://blah.au.auth0.com/userinfo");
request.Headers.Add("Authorization", accessToken);
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
However, this doesn’t seem very scalable. If I have 5 endpoints on that API, all of which require the user’s email address, that’s already at least 5 calls to /userinfo (just for a single user).
It would be much easier if the required information was included in the access_token.
This is the MVC services code:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => HostingEnvironment.IsProduction();
options.MinimumSameSitePolicy = SameSiteMode.None;
});
// Add authentication services
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("Auth0", options => {
// Set the authority to your Auth0 domain
options.Authority = $"https://{Configuration["Auth0:Domain"]}";
// Configure the Auth0 Client ID and Client Secret
options.ClientId = Configuration["Auth0:ClientId"];
options.ClientSecret = Configuration["Auth0:ClientSecret"];
// Set response type to code
options.ResponseType = "code";
// Configure the scope
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("read:messages");
// Set the callback path, so Auth0 will call back to http://localhost:3000/callback
// Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
options.CallbackPath = new PathString("/callback");
// Configure the Claims Issuer to be Auth0
options.ClaimsIssuer = "Auth0";
// Saves tokens to the AuthenticationProperties
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
// If you want to call an API from your MVC application, you need to obtain an Access Token issued for the API you want to call.
// To obtain the token, pass an additional audience parameter containing the API identifier to the Auth0 authorization endpoint.
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("audience", "https://api.blah.net");
return Task.FromResult(0);
},
// handle the logout redirection
OnRedirectToIdentityProviderForSignOut = (context) =>
{
var logoutUri = $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}";
var postLogoutUri = context.Properties.RedirectUri;
if (!string.IsNullOrEmpty(postLogoutUri))
{
if (postLogoutUri.StartsWith("/"))
{
// transform to absolute
var request = context.Request;
postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
}
logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}";
}
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
}
};
});
services.AddControllersWithViews();
}