How to create custom Authorization Attribute for GraphQL Endpoints to allow users base on their “permission” claim in access token

How to create custom Authorization Attribute for GraphQL Endpoints to allow users base on their “permission” claim in access token


0

I’m currently working on a .NET Core project that utilizes both regular API endpoints and GraphQL endpoints using HotChocolate. I implemented the authentication for both endpoints and it working.

 [Authorize] // this attribute from using Microsoft.AspNetCore.Authorization;
 [HttpPost("GetCountryHolidays")]
 public async Task<IList<GetCountryDetails>> GetHolidays(GetHolidaysCommand command)
 {
      return await _mediator.Send(command);
 }

Graphql endpoint

 [Authorize]  // this attribute from HotChocolate.AspNetCore.Authorization;
 public async Task<bool> CreateUser(User Command)
 {
      await _mediator.Send(query);
      return true;
 }

above implementation is working.

Then I need to implement the authorization. I need to check the "permission" claim in the access token. so I have implemented a custom authorization attribute called "HasPermission" to check for permissions based on claims in the access token. This attribute works perfectly for regular API endpoints with the [Authorize] attribute, but it doesn’t seem to work for GraphQL endpoints.

this is my "HasPermission" implementation

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;

namespace MySampleProject.Tenant.Api
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class HasPermissionAttribute : Attribute, IAuthorizationFilter
    {
        private string[] permissions { get; set; }

        private bool allowEServiceUser { get; set; }

        public HasPermissionAttribute(params string[] permissions)
        {
            if (permissions != null && permissions.Length > 0 && permissions.Any(x => string.IsNullOrWhiteSpace(x)))
                throw new ArgumentNullException("permissions", "Permissions value is not submitted or invalid!");
            this.permissions = permissions;
            this.allowEServiceUser = false;
        }

        public HasPermissionAttribute(bool allowEServiceUser = false, params string[] permissions)
        {
            if (permissions != null && permissions.Length > 0 && permissions.Any(x => string.IsNullOrWhiteSpace(x)))
                throw new ArgumentNullException("permissions", "Permissions value is not submitted or invalid!");

            this.permissions = permissions;
            this.allowEServiceUser = allowEServiceUser;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if ((permissions != null && permissions.Length > 0) && !(permissions.Any(x => string.IsNullOrEmpty(x))))
            {
                if (!context.HttpContext.HasPermisions(permissions, allowEServiceUser))
                {
                    context.Result = new UnauthorizedResult();
                }
            }
        }
    }

    public static class HttpContextExtension
    {
        public static bool HasPermisions(this HttpContext context, string[] permissionKeys, bool allowEserviceUser = false)
        {
            if (context == null)
                return false;

            List<string> permissions = context.User.Claims.Where(x => x.Type == "permissions").Select(x => x.Value).ToList();
            return permissions.Intersect(permissionKeys).Any();

        }
    }
}

this is how I call it with regular API endpoints

[HttpPost("admin")]
[HasPermission("CAN_ADMIN_ONLY")]
public bool TestAdmin()
{
   return true;
}

it works with regular API endpoints. However, when I use the same HasPermission attribute on a GraphQL endpoint, it doesn’t seem to have any effect, and the endpoint remains accessible without any permission checks:

Is there something specific I need to do to make it work for GraphQL endpoints with HotChocolate? Any insights or guidance would be greatly appreciated.


Load 7 more related questions


Show fewer related questions

0



Leave a Reply

Your email address will not be published. Required fields are marked *