Code Monkey home page Code Monkey logo

Comments (11)

joemcbride avatar joemcbride commented on July 18, 2024 6

You need to add [Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)] to your GraphQLController to make ASP.NET Core run the jwt authorization. See the following docs.

Provide a UserContext class that implements IProvideClaimsPrincipal.

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

Provide that UserContext to the DocumentExecutor.

var executionOptions = new ExecutionOptions
{
  ...
  UserContext = new GraphQLUserContext
  {
    // this is the User on your controller
    // which is populated from your jwt
    User = User
  }
};

Register the AuthorizationValidationRule (and other required services).

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IAuthorizationEvaluator, AuthorizationEvaluator>();
services.AddTransient<IValidationRule, AuthorizationValidationRule>();

Inject those validation rules into the ctor of your GraphQLController.

public GraphQLController(IDocumentExecuter documentExecuter,
            ISchema schema,
            ILogger<GraphQLController> logger,
           IEnumerable<IValidationRule> validationRules)
        {
            _documentExecuter = documentExecuter;
            _schema = schema;
            _logger = logger;
           _validationRules = validationRules;
        }
}

Add the rules to the ExecutionOptions.

var executionOptions = new ExecutionOptions
{
  ...
  ValidationRules = DocumentValidator.CoreRules().Concat(_validationRules).ToList();
};

from authorization.

som-nitjsr avatar som-nitjsr commented on July 18, 2024 3
services.AddGraphQLAuth(_ =>
            {
               // _.AddPolicy("dev", p => p.RequireClaim("role", "dve") || p.RequireClaim("role", "admin"));
                _.AddPolicy("AdminPolicy", p => p.RequireClaim("Role", "Manager"));

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

            services.AddSingleton(s =>
            {
                var authSettings = new AuthorizationSettings();
                configure(authSettings);
                return authSettings;
            });
      
  public class GraphQLUserContext : IProvideClaimsPrincipal
        {
            public ClaimsPrincipal User { get; set; }
        }

from authorization.

benmccallum avatar benmccallum commented on July 18, 2024 1

Is adding .UseAuthentication(); enough? My HttpContext.User never seems to have any claims or properties set though I'm not 100% sure if this is an issue with the token or not.

Turns out I had an expired JWT. The following should be enough for anyone else who ends up here.

In ConfigureServices:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => options.AddAuth0JwtBearerOptions(Configuration));

In Configure:

app.UseAuthentication(); // must be before it needs to be used
app.UseGraphQL<ISchema>();

from authorization.

joemcbride avatar joemcbride commented on July 18, 2024

You would handle the JWT outside of GraphQL Auth. See https://developer.okta.com/blog/2018/03/23/token-authentication-aspnetcore-complete-guide

You would then create GraphQL Auth Policies that check the claims in the ClaimsPrincipal. The ClaimsPrincipal gets populated from the JWT.

from authorization.

Tochemey avatar Tochemey commented on July 18, 2024

Hello,

Please can you educate me on how to create the graphql auth policy. Also I have found that the examples are using middleware. However I am not using a middleware approach.

from authorization.

Tochemey avatar Tochemey commented on July 18, 2024

Hello

I have tried this:

            services.TryAddTransient<IHttpContextAccessor, HttpContextAccessor>();

            services.AddSingleton<IJwtFactory, JwtFactory>();
            var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

            // Configure JwtIssuerOptions
            services.Configure<JwtIssuerOptions>(
                options =>
                {
                    options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
                    options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
                    options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
                });

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

                ValidateAudience = true,
                ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

                ValidateIssuerSigningKey = true,
                IssuerSigningKey = _signingKey,

                RequireExpirationTime = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };

            services.AddAuthentication(
                options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(
                configureOptions =>
                {
                    configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
                    configureOptions.TokenValidationParameters = tokenValidationParameters;
                    configureOptions.SaveToken = true;
                });

            services.TryAddSingleton<IAuthorizationEvaluator, AuthorizationEvaluator>();
            services.AddTransient<IValidationRule, AuthorizationValidationRule>();

            services.TryAddSingleton(s =>
            {
                var authSettings = new AuthorizationSettings();
                authSettings.AddPolicy("AuthPolicy",
                    builder =>
                    {
                        builder.RequireClaim(ClaimTypes.NameIdentifier);
                        builder.RequireClaim(ClaimTypes.Country);
                    });
                return authSettings;
            });

I would like to know what else should I do to get the authenticated user. This is my graphql controller:

    public class GraphQLController : Controller
    {
        private readonly IDocumentExecuter _documentExecuter;
        private readonly ILogger _logger;
        private readonly ISchema _schema;

        /// <summary>
        /// </summary>
        /// <param name="documentExecuter"></param>
        /// <param name="schema"></param>
        /// <param name="logger"></param>
        public GraphQLController(IDocumentExecuter documentExecuter,
            ISchema schema,
            ILogger<GraphQLController> logger)
        {
            _documentExecuter = documentExecuter;
            _schema = schema;
            _logger = logger;
        }

        /// <summary>
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
        {
            if (query == null) throw new ArgumentNullException(nameof(query));

            try
            {
                var inputs = query.Variables.ToInputs();
                var executionOptions = new ExecutionOptions
                {
                    Schema = _schema,
                    Query = query.Query,
                    Inputs = inputs,
                    ExposeExceptions = true,
                    EnableMetrics = true
                };

                var result = await _documentExecuter.ExecuteAsync(executionOptions).ConfigureAwait(false);

                if (result.Errors?.Count > 0)
                {
                    _logger.LogWarning($"Errors: {JsonConvert.SerializeObject(result.Errors)}");
                    return BadRequest(result);
                }
                return Ok(result);
            }
            catch (Exception e)
            {
                _logger.LogError(e, string.Empty);
            }

            return StatusCode((int) HttpStatusCode.InternalServerError);
        }
    }


from authorization.

Tochemey avatar Tochemey commented on July 18, 2024

Thank you so much for the explanation.

from authorization.

som-nitjsr avatar som-nitjsr commented on July 18, 2024

HI @joemcbride I am using app.UseGraphQLHttp(options);
I am not using controller.
my issue is I have to call jwt token validation manually. I wanted to get it called automatically.

from authorization.

benmccallum avatar benmccallum commented on July 18, 2024

I've got a similar issue to you @som-nitjsr. Just trying to figure out how this works when using graphql-dotnet/server. We can't just add the Authorize attribute onto our controller to make the AuthorizeEvents trigger. What did you end up doing?

from authorization.

benmccallum avatar benmccallum commented on July 18, 2024

cheers :)

from authorization.

ralle93 avatar ralle93 commented on July 18, 2024

I am currently building a SPA aswell. That uses JWT. Can you guys show me the code for your project. I can't seem to make it work in any way...

from authorization.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.