Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Umbrella Dotnet Scaffold Resource Auth Handler

ASecurity

Scaffold a resource-based ASP.NET Core IAuthorizationHandler for an entity, handling row-level access control (ownership, role, operation-specific checks). Used when AuthorizationXxxChecksEnabled is not suppressed on a controller or controller service.

8 stars
0 votes
0 copies
0 views
Added 9/22/2026
toolsapisecurity

Works with

api

Security Analysis

A100/100

Scanned 9/22/2026

Install to Claude Code

$npx -y skills add umbrella-libraries/Umbrella --skill umbrella-dotnet-scaffold-resource-auth-handler --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Umbrella Dotnet Scaffold Resource Auth Handler?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Umbrella Dotnet Scaffold Resource Auth Handler
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/umbrella-libraries-umbrella-dotnet-scaffold-resource-auth-handler-c92515e4/badge)](https://www.skillsdirectory.com/skills/umbrella-libraries-umbrella-dotnet-scaffold-resource-auth-handler-c92515e4)

More formats (shields.io, HTML) on the badges page.

Download with Pro
Files
SKILL.md
---
name: umbrella-dotnet-scaffold-resource-auth-handler
description: 'Scaffold a resource-based ASP.NET Core IAuthorizationHandler for an entity, handling row-level access control (ownership, role, operation-specific checks). Used when AuthorizationXxxChecksEnabled is not suppressed on a controller or controller service.'
---

# Scaffold Resource Authorization Handler

## Purpose

Add a resource-based `IAuthorizationHandler` that enforces row-level access control for a specific entity type. The Umbrella base controller and controller service internally call `IAuthorizationService.AuthorizeAsync(user, entity, policyName)` for each CRUD operation when the corresponding `AuthorizationXxxChecksEnabled` property is not suppressed. This handler is what ASP.NET Core invokes in response to those calls.

**When is this needed?** By default, the controller skills set all `AuthorizationXxxChecksEnabled` overrides to `false`, which bypasses the built-in resource-level checks. If you remove those overrides (or set any to `true`) for a specific operation, a matching `IAuthorizationHandler<OperationAuthorizationRequirement, TEntity>` must be registered — otherwise access will be denied for all users.

**Relationship to `[Authorize(PolicyName)]`:** The controller-level `[Authorize]` attribute is a coarse-grained gate (is the user authenticated and in the right role?). The resource auth handler is the fine-grained gate (can this specific user access this specific entity row?). Both must pass.

## Discovery (read these before writing anything)

1. Read 2–3 existing resource auth handlers in `Web\<AppName>.Web.Server\Security\Handlers\` to understand the role-check patterns, how ownership is verified (e.g. `resource.AppUserId == context.User.GetId<int>()`), and how operation-specific logic is structured.
2. Confirm which `CoreItemOperations` are used (`Create`, `Read`, `Update`, `Delete`) — these are the requirement values the base controller passes.
3. Read the entity type to understand what ownership or relationship fields are available (e.g. `AppUserId`, `LearningProviderId`).
4. Read `Web\<AppName>.Web.Server\IServiceCollectionExtensions.cs` — find the `// Authorization Handlers` section to see the existing registration style.
5. Confirm the target controller or controller service already exists and identify the exact `AuthorizationXxxChecksEnabled` override to remove. If it does not exist, stop and use `umbrella-dotnet-scaffold-api-repo-controller` or `umbrella-dotnet-scaffold-api-data-service-controller` first; do not create an ad-hoc controller inside this security-only workflow.

---

## Step 1 -- Create the handler

**File:** `Web\<AppName>.Web.Server\Security\Handlers\<Name>AuthorizationHandler.cs`

```csharp
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using <AppName>.Core.Domain.Entities;
using Umbrella.AspNetCore.WebUtilities.Security.Policies;

namespace <AppName>.Web.Server.Security.Handlers;

internal sealed class <Name>AuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, <Name>>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        OperationAuthorizationRequirement requirement,
        <Name> resource)
    {
        if (context.User.GetId<int>() == resource.AppUserId)
            context.Succeed(requirement);

        return Task.CompletedTask;
    }
}
```

### Operation-specific logic

When different operations need different checks, switch on `requirement`:

```csharp
protected override Task HandleRequirementAsync(
    AuthorizationHandlerContext context,
    OperationAuthorizationRequirement requirement,
    <Name> resource)
{
    bool succeed = requirement switch
    {
        var operation when operation == CoreItemOperations.Read =>
            context.User.GetId<int>() == resource.AppUserId,

        var operation when operation == CoreItemOperations.Create ||
                           operation == CoreItemOperations.Update ||
                           operation == CoreItemOperations.Delete =>
            context.User.IsInRole(nameof(AppRoleType.Administrator)),

        _ => false
    };

    if (succeed)
        context.Succeed(requirement);

    return Task.CompletedTask;
}
```

### Role-aware ownership (multi-role pattern)

When higher roles bypass ownership checks:

```csharp
protected override Task HandleRequirementAsync(
    AuthorizationHandlerContext context,
    OperationAuthorizationRequirement requirement,
    <Name> resource)
{
    bool succeed = false;

    if (context.User.IsInRole(nameof(AppRoleType.System)) ||
        context.User.IsInRole(nameof(AppRoleType.SuperAdministrator)) ||
        context.User.IsInRole(nameof(AppRoleType.Administrator)))
    {
        succeed = true;
    }
    else if (context.User.IsInRole(nameof(AppRoleType.Student)))
    {
        succeed = requirement == CoreItemOperations.Read &&
                  resource.AppUserId == context.User.GetId<int>();
    }

    if (succeed)
        context.Succeed(requirement);

    return Task.CompletedTask;
}
```

**Rules:**
- `internal sealed class` — registered and resolved via `IAuthorizationHandler`; never needs to be referenced directly.
- Inherit directly from `AuthorizationHandler<OperationAuthorizationRequirement, TEntity>` — there is no Umbrella-specific base class for resource handlers.
- Call `context.Succeed(requirement)` when authorized. **Never call `context.Fail()`** — per ASP.NET Core convention, non-success is the default and explicit failure blocks all other handlers.
- The handler is only invoked when the base controller/service calls `AuthorizeAsync` for the matching entity type — it does not need to guard against being called for the wrong type.
- Use `CoreItemOperations.Create`, `CoreItemOperations.Read`, `CoreItemOperations.Update`, `CoreItemOperations.Delete` for comparisons (not string literals).

---

## Step 2 -- Enable the auth check on the controller or controller service

In the controller (Pattern 1) or controller service (Pattern 2), remove the suppression override(s) for the operations this handler should enforce. The base class defaults to `true` (enabled) — only operations explicitly suppressed with `=> false` bypass the handler.

**Pattern 1 controller — enable Read check:**
```csharp
// Remove this line (or omit it):
protected override bool AuthorizationReadChecksEnabled => false;

// Keep suppressed for operations the handler does not cover:
protected override bool AuthorizationSlimReadChecksEnabled => false;
protected override bool AuthorizationCreateChecksEnabled => false;
protected override bool AuthorizationUpdateChecksEnabled => false;
protected override bool AuthorizationDeleteChecksEnabled => false;
```

**Pattern 2 controller service — same approach:**
Remove the suppression override for the targeted operation on `<Name>ControllerService`.

---

## Step 3 -- Register in DI

**File:** `Web\<AppName>.Web.Server\IServiceCollectionExtensions.cs` — `// Authorization Handlers` section, alphabetical order:

```csharp
_ = services.AddScoped<IAuthorizationHandler, <Name>AuthorizationHandler>();
```

---

## Analyzer compatibility

Before finishing, read `.ai-shared\bundles\umbrella\analyzer-compatibility.md` and build the affected projects with their installed analyzers enabled. Treat diagnostics introduced by the generated or changed code as defects in this workflow.

## Verification

1. The handler is `internal sealed class` inheriting `AuthorizationHandler<OperationAuthorizationRequirement, <EntityType>>`.
2. `HandleRequirementAsync` calls `context.Succeed(requirement)` on the success path and **never** calls `context.Fail()`.
3. The corresponding `AuthorizationXxxChecksEnabled` override is absent (or `true`) on the controller/controller service for any operation this handler covers.
4. `services.AddScoped<IAuthorizationHandler, <Name>AuthorizationHandler>()` is present in `IServiceCollectionExtensions.cs`.
5. If the handler only covers some operations (e.g. Read only), the remaining operations on the controller are still suppressed with `=> false`.
6. A test identity can be constructed that the handler denies (e.g. a non-owner user id or missing role). A handler that succeeds for every authenticated user makes the imperative 403 path untestable in integration tests — if that is intentional, note it so test generation skips the 403 tests.

Attribution

umbrella-librariesumbrella-libraries
View sourceMore from umbrella-libraries →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

ucoz-landing-skill

Playbook for creating and editing uCoz landing pages via MCP tools (`templates_tool`, `ftp_tool`, `modules_tool`). Use for tasks such as: "build a landing page", "update the homepage as a landing page", "create a promo page on the homepage", "add a lead form / menu / SEO to the homepage". Homepage: `page_list`, `page_get`; first publish — `page_update` with full `page_tmpl`; HTML edits after generation — `patch_template` (module_id=2, template_id=1), not `update_template`. Activate the mail f...

107 votes

Paperclip

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

813271 votes

Daw Music

Digital Audio Workstation usage, music composition, interactive music systems, and game audio implementation for immersive soundscapes.

761 votes

Instantly Rdsthomas Mission Control

Instantly.ai cold email outreach API - manage campaigns, leads, accounts, and analytics. Use for cold email automation, lead management, campaign creation/monitoring, and email account warmup.

761 votes

Caveman Compress

Compress natural language memory files (CLAUDE.md, todos, preferences) into caveman format to save input tokens. Preserves all technical substance, code, URLs, and structure. Compressed version overwrites the original file. Human-readable backup saved as FILE.original.md. Trigger: /caveman-compress FILEPATH or "compress memory file"

1066600 votes
View all in tools →