I am setting up an web application on ASP .NET Core 5 with Google Auth. I want to be able to mark certain pages with an Authorize attribute to only allow users with a given Role to access. The access token sent by Google only contains name and email, not which group or role the user is assigned to. So I am trying to obtain the role with a call to the API, but how do I do that?
This is my Startup.cs
public class Startup
{
private IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddGoogleOpenIdConnect (async options =>
{
var googleAuthenticationSection = Configuration.GetSection("Authentication:Google");
options.ClientId = googleAuthenticationSection["ClientId"];
options.ClientSecret = googleAuthenticationSection["ClientSecret"];
options.CallbackPath = new("/signin-oidc");
options.Scope.Add("https://www.googleapis.com/auth/admin.directory.group.readonly");
options.Scope.Add("https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly");
options.Scope.Add("https://www.googleapis.com/auth/admin.directory.user.readonly");
options.ClaimActions.MapJsonKey(ClaimTypes.Role, "role", "string");
options.Events = new OpenIdConnectEvents
{
OnMessageReceived = context =>
{
if (!string.IsNullOrEmpty(context.ProtocolMessage?.Error))
{
context.Response.Redirect($"/AccessDenied?error={context.ProtocolMessage.Error}&error_description={context.ProtocolMessage.ErrorDescription}");
context.HandleResponse();
}
return Task.CompletedTask;
}
};
// start of attempt to retrieve Role from Google Directory API
var credential = await GoogleAuthProvider.GetCredentialAsync();
var googleApiService = new DirectoryService(new BaseClientService.Initializer { HttpClientInitializer = credential });
var getRole = new RolesResource.GetRequest(googleApiService, "Zvi", "Owner");
var role = await getRole.ExecuteAsync();
// end of attempt to retrieve Role
})
.AddCookie();
services.
AddAuthorization(options =>
{
options.AddPolicy("WriteAccess", x => x.RequireClaim(ClaimTypes.Role, "Owner"));
});
The problem is that GoogleAuthProvider is not injected into the Startup class so I cannot use it. I want to put it here so that I can insert a new claim with that value once it has been retrieved.
Of course, if anyone has a better way of getting the user's Role (or Group) without making an API call that would be better.
Try to use OnUserInformationReceived. Invoked when user information is retrieved from the UserInfoEndpoint.
You can Gets or sets the user information payload from UserInformationReceivedContext.User. :