'Using `await` in AuthorizationHandler

I have a AuthorizationHandler depending on a Service offering async methods for .NET Core 3.1's Authorization Middleware. I have o call some of these async methods inside the HandleRequirementAsync method. The overall code looks like this:

{
    public class MyAuthorizationHandler : AuthorizationHandler<MyRequirement, Tuple<string, string>>
    {
        private readonly IAuthIntelRepository authIntelRepository;
        public UserAssistanceAuthorizationHandler(IAuthIntelRepository authIntelRepository)
        {
            this.authIntelRepository = authIntelRepository;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
        {
            //some async calls to authIntelRepository
            if (/*someCondition*/false)
            {
                context.Succeed(requirement);
            }
            return Task.CompletedTask;
        }
    }

    public class MyRequirement : IAuthorizationRequirement { }
}

As soon is I use an await statement though, I get an error that the signature isn't explicitly set as async. Adding async to the inherited method's signature causes the following error. a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?

This thread elaborates a similar issue but the solution doesn't seem to work in .NET Core 3.1.

Using Result in the following manner works, but AFAIK this will result in a blocking call:

Task<Object> obj= this.authIntelRepository.getSomeAsync(...);
obj.Result.property //do Something to check the requirement

I'm not sure what the correct solution would look like here.



Solution 1:[1]

If the return type of your async method is Task, then, apart from the await keyword, your treat your method as if it was void returning:

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
{
    await authIntelRepository....
    if (/*someCondition*/false)
    {
         context.Succeed(requirement);
     }
     return;
}

Solution 2:[2]

Adding async to HandleRequirementAsync and use await to call the async method inside HandleRequirementAsync breaks the authorization, try calling external db or httpClient (delays), Type in the browser the route address with authorization. The route will be redirected to the non authorized page even though the context.Succeed(requirement) is executed .

The working solution for me (blazor server .NET 5) is keeping the HandleRequirementAsync as it is, execute the async method we need to call using pattern for executing async method inside non async method.

My sample working code derived from https://stackoverflow.com/a/43148321/423356

my sample async method:

public async Task<IList<Permission>> GetGroupPermissions(int userId)
{
    HttpResponseMessage response = await _httpClient.GetAsync(string.Format("Auth/GroupPermissions/{0}", userId));

    try
    {
        var payload = await response.Content.ReadFromJsonAsync<List<Permission>>();
        response.EnsureSuccessStatusCode();

        return payload;
    }
    catch
    {
        return new List<Permission>();
    }

}

HandleRequirementAsync:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
    var t2 = (Task.Run(() => GetGroupPermissions(userId)));
    t2.Wait();
    var userGroupPermissions = t2.Result;
    

    if (!userGroupPermissions.Contains(requirement.Permission))
    {
        //context.Fail(); //no need to fail, other requirement might success
        return Task.CompletedTask;
    }

    context.Succeed(requirement);

    return Task.CompletedTask;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Paulo Morgado
Solution 2 kite