Search code examples
c#asp.net-coreauthorizationidentityserver4

What's the technical advantage of claim/role/policy authorization as opposed to plain check of a user's ID?


I used Identity Server and protected endpoints with policies and roles. Those are reflected in the access token I'm distributing to the client. Today, I got the suggestion that instead of protecting a method like this:

[Authorize(Policy = "Elevated"), HttpGet("metadata")]
public IActionResult GetTenantMetadata() { ... }

we could skip the role section of the JWT and only do the following.

[Authorize, HttpGet("metadata")]
public IActionResult GetTenantMetadata() { ... }

Then, in the Startup.cs, we'd register a custom handler like this.

services.AddHttpContextAccessor();
services.AddTransient<IAuthorizationHandler, HeaderHandler>();

The actual security would be then performed in the handler based on the sub value from the token. No roles, no scopes no nothing. To me, it appears intuitively ill-advised putting a lot of responsibility on me to create the protective logic, instead of relying on IDS and people way smarter than me. All the solutions I've seen deal with security using claims and roles. So my gut feeling says it's a bad idea.

protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        CustomRequirement requirement)
    {
        HttpRequest request = Accessor.HttpContext.Request;
        string param = request.Headers.SingleOrDefault(a => a.Key == "param1");
        string someAccess = dbContext.GetAccess(param, context.User.GetUserId());

        bool authorized = SomeEvaluation(param, someAccess);
        if (authorized) context.Succeed(requirement);
        else context.Fail();

        return Task.CompletedTask;
    }

However, I wasn't able to motivate my choice (other than the guts and others' samples), so finally, I got unsure. I'm humble to understand that if I can't explain why, then maybe I'm wrong.

I googled claims based security and roles policies security etc. but I could come up with a name for the suggested alternative. Consequently, I haven't found any material discussing that matter.

What is such a custom authorization method called and what's the advantage/caveat of it?


Solution

  • It's still claims authorization, just not a good / practical one: you're only using the sub claim. There's no reason to throw away/not use perfectly good claims provided by a trusted identity provider.

    First, letting clients send the user ID via a header is a security risk. How would you know if it's not tampered with, and the user is not pretending to be an admin? You can't, that's why you ask an ID provider to authenticate the user and sign a token for identification.

    Second, cherry-picking the user ID and fetching other user claims at runtime from a database or API could work, but it may not always possible (app doesn't keep user data / delegates authentication to a 3rd party) or feasible (high traffic application, too many db lookups).

    To authorize an action, you can declare policies with assertions. But for more advanced or imperative checks, you have the option to implement an AuthorizationHandler and imperatively allow/block an action.
    It's useful for resource-based authorization, but an overkill for what would be a single line of code if the claims you need are already provided in the access token.

    Further info