5

I am using for GraphQL for .NET package for graphql. But I couldn't understand how can I authentication with JWT in graphql query or mutation.

I read the guide about authorization but I couldn't accomplish.

I need help with GraphQL for .NET authentication.

Any help will be appreciated.

Thanks

4
  • Not sure I understand the relation of the two. With JWT you authenticate the user against your app. By the time he hits the controller action, the user is populated with claims and can be used with the example you linked? Commented May 31, 2018 at 16:49
  • But we should authorize the graphql query using JWT payload? Commented May 31, 2018 at 17:01
  • From the first look (didn't look into the details) the linked example only uses IPrincipal / ClaimsPrincipal respectively. All you do is check if user has specific claims (in this example). The claims where already populated earlier during the request. Read, you send the claim to your API which populates the User Property with claims and all other information. At this point you don't need to worry anymore if the user authenticated via jwt, cookie or something else Commented May 31, 2018 at 17:06
  • Ok I understood. Thanks. But in the same guide it shows about implementation. But it has many errors.May I need this? Here implementation: github.com/graphql-dotnet/authorization Commented May 31, 2018 at 18:05

2 Answers 2

2

The guide is around authorization. The step you're looking for is the authentication and since graphql can be implemented using a ASP.Net API controller, you can implement JWT authentication as you would with any controller.

Here is a sample grapql controller using an Authorize attribute. You could, however, implement this using filter or if you want full control, custom middleware.

[Route("api/[controller]")]
[ApiController]
[Authorize]
public class GraphQLController : ControllerBase
{
    private readonly IDocumentExecuter executer;
    private readonly ISchema schema;

    public GraphQLController(IDocumentExecuter executer, ISchema schema)
    {
        this.executer = executer;
        this.schema = schema;
    }

    [HttpPost]
    public async Task<ActionResult<object>> PostAsync([FromBody]GraphQLQuery query)
    {
        var inputs = query.Variables.ToInputs();
        var queryToExecute = query.Query;

        var result = await executer.ExecuteAsync(o => {
            o.Schema = schema;
            o.Query = queryToExecute;
            o.OperationName = query.OperationName;
            o.Inputs = inputs;

            o.ComplexityConfiguration = new GraphQL.Validation.Complexity.ComplexityConfiguration { MaxDepth = 15};
            o.FieldMiddleware.Use<InstrumentFieldsMiddleware>();
        }).ConfigureAwait(false);

        return this.Ok(result);
    }
}

public class GraphQLQuery
{
    public string OperationName { get; set; }
    public string Query { get; set; }
    public Newtonsoft.Json.Linq.JObject Variables { get; set; }
}

In the Startup.cs I have configured JWT bearer token authentication.

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

2

I myself struggled for two days as well. I'm using https://github.com/graphql-dotnet/authorization now with the setup from this comment (from me): https://github.com/graphql-dotnet/authorization/issues/63#issuecomment-553877731

In a nutshell, you have to set the UserContext for the AuthorizationValidationRule correctly, like so:

public class Startup
{
    public virtual void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddGraphQLAuth(_ =>
        {
            _.AddPolicy("AdminPolicy", p => p.RequireClaim("Role", "Admin"));
        });
        services.AddScoped<IDependencyResolver>(x => new FuncDependencyResolver(x.GetRequiredService));
        services.AddScoped<MySchema>();
        services
            .AddGraphQL(options => { options.ExposeExceptions = true; })
            .AddGraphTypes(ServiceLifetime.Scoped);
        ...
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    {
        ...
        app.UseMiddleware<MapRolesForGraphQLMiddleware>(); // optional, only when you don't have a "Role" claim in your token
        app.UseGraphQL<MySchema>();
        ...
    }
}

public static class GraphQLAuthExtensions
{
    public static void AddGraphQLAuth(this IServiceCollection services, Action<AuthorizationSettings> configure)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IAuthorizationEvaluator, AuthorizationEvaluator>();
        services.AddTransient<IValidationRule, AuthorizationValidationRule>();

        services.AddTransient<IUserContextBuilder>(s => new UserContextBuilder<GraphQLUserContext>(context =>
        {
            var userContext = new GraphQLUserContext
            {
                User = context.User
            };

            return Task.FromResult(userContext);
        }));

        services.AddSingleton(s =>
        {
            var authSettings = new AuthorizationSettings();
            configure(authSettings);
            return authSettings;
        });
    }
}

public class GraphQLUserContext : IProvideClaimsPrincipal
{
    public ClaimsPrincipal User { get; set; }
}

public class MapRolesForGraphQLMiddleware
{
    private readonly RequestDelegate _next;

    public MapRolesForGraphQLMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // custom mapping code to end up with a "Role" claim
        var metadata = context.User.Claims.SingleOrDefault(x => x.Type.Equals("metadata"));

        if (metadata != null)
        {
            var roleContainer = JsonConvert.DeserializeObject<RoleContainer>(metadata.Value);
            (context.User.Identity as ClaimsIdentity).AddClaim(new Claim("Role", string.Join(", ", roleContainer.Roles)));
        }

        await _next(context);
    }
}

public class RoleContainer
{
    public String[] Roles { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.