A toolset for authorizing access to graph types for GraphQL.NET. It provides a validation rule that checks all of the Graph Types in the given GraphQL operation (query/mutation/subscription) to see if they have authorization policies applied to them and evaluates these policies if any.
Provides the following packages:
| Package | Downloads | NuGet Latest |
|---|---|---|
| GraphQL.Authorization |
You can get all preview versions from GitHub Packages. Note that GitHub requires authentication to consume the feed. See here.
If you came here in search for GraphQL authorization for the ASP.NET Core applications, then it makes sense to look into the server project and its GraphQL.Server.Authorization.AspNetCore package. Although you will be able to integrate GraphQL authorization with the help of classes from the current repository, the GraphQL.Server.Authorization.AspNetCore package is much better adapted to work within the ASP.NET Core applications.
- Register the necessary authorization classes in your DI container:
IValidationRule/AuthorizationValidationRuleIAuthorizationService/DefaultAuthorizationServiceIClaimsPrincipalAccessor/DefaultClaimsPrincipalAccessorIAuthorizationPolicyProvider/DefaultAuthorizationPolicyProvider
- If you use
DefaultClaimsPrincipalAccessorthen provide a customUserContextclass that implementsIProvideClaimsPrincipal. - Add policies to the
AuthorizationSettings. - Apply a policy to a
GraphTypeorFieldType(both implementIProvideMetadata):- using
AuthorizeWith(string policy)extension method - or with
GraphQLAuthorizeattribute if using Schema + Handler syntax.
- using
- The
AuthorizationValidationRulewill run and verify the policies based on the registered policies. - You can write your own
IAuthorizationRequirementand an extension method to add this requirement toAuthorizationPolicyBuilder.
-
Fully functional basic Console sample.
-
Fully functional ASP.NET Core sample.
Use AuthorizeWith extension method on IGraphType or IFieldType.
public class MyType : ObjectGraphType
{
public MyType()
{
this.AuthorizeWith("AdminPolicy");
Field<StringGraphType>("name").AuthorizeWith("SomePolicy");
}
}Use GraphQLAuthorize attribute on type, method or property.
[GraphQLAuthorize(Policy = "MyPolicy")]
public class MutationType
{
[GraphQLAuthorize(Policy = "AnotherPolicy")]
public async Task<string> CreateSomething(MyInput input)
{
return await SomeMethodAsync(input);
}
[GraphQLAuthorize(Policy = "SuperPolicy")]
public string SomeProperty => Guid.NewGuid().ToString();
}You can add your own requirements to the authorization framework to extend it.
Create your own IAuthorizationRequirement class and add that requirement to your policy.
public class OnlyMondayRequirement : IAuthorizationRequirement
{
public Task Authorize(IAuthorizationContext context)
{
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
context.Succeed(this);
}
}
public static class MyAuthorizationPolicyBuilderExtensions
{
public static AuthorizationPolicyBuilder RequireMonday(this AuthorizationPolicyBuilder builder)
{
builder.AddRequirement(new OnlyMondayRequirement());
return builder;
}
}
public static void ConfigureAuthorizationServices(ServiceCollection services)
{
services
.AddSingleton<IValidationRule, AuthorizationValidationRule>()
.AddSingleton<IAuthorizationService, DefaultAuthorizationService>()
.AddSingleton<IClaimsPrincipalAccessor, DefaultClaimsPrincipalAccessor>()
.AddSingleton<IAuthorizationPolicyProvider>(provider =>
{
var authSettings = new AuthorizationSettings();
authSettings.AddPolicy("MyPolicy", b => b.RequireMonday());
return new DefaultAuthorizationPolicyProvider(authSettings);
})
}Authorization requirement (IAuthorizationRequirement) only checks the compliance of
the current execution state to some criteria. If the requirement is satisfied, then
it is marked as 'passed' and the next requirement is checked. If all requirements are
satisfied, then the validation rule returns a successful result. Otherwise for each
unsatisfied requirement, the validation rule will add an authorization error in the
ValidationContext. The text of this error may not suit you, especially if you write
your own authorization requirements because by default you will see only You are not
authorized to run this query text which does not contain any details about your
requirement. This is done for security reasons but you can override the default behavior.
Option 1. If you are satisfied with the existing error messages and you only want
to add error message for your own authorization requirement, then inherit your authorization
requirement from IAuthorizationRequirementWithErrorMessage interface.
public class OnlyMondayRequirement : IAuthorizationRequirementWithErrorMessage
{
public Task Authorize(IAuthorizationContext context)
{
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
context.Succeed(this);
}
public string ErrorMessage => "Access is allowed only on Mondays.";
}Option 2. If you want to get full control over the whole error message for authorization
process then inherit from AuthorizationValidationRule and override AddValidationError
or BuildErrorMessage methods. Then register CustomAuthorizationValidationRule class
instead of AuthorizationValidationRule class in your DI container.
Option 3. Another way to get full control over the whole error message sent to client
is to implement IErrorInfoProvider interface. This is one of the interfaces from the
main GraphQL.NET repository. For convenience you may use the ErrorInfoProvider base class.
public class CustomErrorInfoProvider : ErrorInfoProvider
{
public override ErrorInfo GetInfo(ExecutionError executionError)
{
var info = base.GetInfo(executionError);
info.Message = executionError switch
{
AuthorizationError authorizationError => "You shall not pass!",
_ => info.Message,
};
return info;
}
}Then register CustomErrorInfoProvider in your DI container.
services.AddSingleton<IErrorInfoProvider, CustomErrorInfoProvider>();- It is currently not possible to add a policy to Input objects using Schema first approach.