name: noony-guard-system description: Use when implementing authorization, restricting endpoints by permissions, setting up role-based access control (RBAC), checking user permissions, configuring RouteGuards, using GuardSetup presets, implementing ownership-based or team-based access, or adding wildcard/complex permission expressions in Noony handlers.
skill:noony-guard-system
Does exactly this
RouteGuards for authorization: three protection methods (simple, wildcard, complex), GuardSetup presets for environment configuration, permission ordering rules, and RBAC patterns including ownership checks.
When to use
- "Restrict endpoint to specific permissions"
- "Role-based access control (RBAC)"
- "Ownership-based or team-based access"
- "GuardSetup production vs development"
- "Simple vs wildcard vs complex permission checks"
- "Permission guards after authentication"
Do not use this skill when
- For authentication SETUP (token verification) → see AuthenticationMiddleware docs
- For error handling in guards (403 responses) → use
noony-error-handling - For middleware ordering of guards in the pipeline → use
noony-middleware-ordering - For DI in guard middleware → use
noony-dependency-injection - For testing guard authorization → use
noony-testing-handlers
Prerequisites
Guards require:
- AuthenticationMiddleware must run first (sets
context.user) - Path parameters extracted (
noony-path-parameters) before guards that check resource ownership - Correct middleware ordering per
noony-middleware-ordering's canonical order
Steps
Configure guards once at startup with
GuardSetup.production()orGuardSetup.development()→ Seereferences/guard-patterns.md#guardsetup-presetsfor environment presetsPlace guards AFTER
AuthenticationMiddlewarepernoony-middleware-ordering's canonical order — user must exist before checking permissions- Canonical: ErrorHandler → OTel → Auth → Guards → BodyParser → Validation → ...
Ensure path parameters are extracted (
noony-path-parameters) before guards that check resource ownership- Ownership guards need
context.req.params.idto verify the user owns the resource
- Ownership guards need
Use
RouteGuards.requirePermissions()for simple permission checks (most common) → Seereferences/guard-patterns.md#requirepermissions-simple-checksfor examplesUse
RouteGuards.requireWildcardPermissions()for hierarchical patterns likeadmin:*→ Seereferences/guard-patterns.md#requirewildcardpermissions-pattern-matchingfor wildcard syntaxUse inline
before()middleware for complex ownership/team-based checks that need DB lookups → Seereferences/guard-patterns.md#complex-authorization-ownership-teamsfor patternsTest guard authorization with mock users and permission arrays → See
noony-testing-handlersfor guard testing examples
Rules
AuthenticationMiddlewareMUST run before guards — guards needcontext.userpopulated- Guards check
context.user.permissionsarray for required permissions GuardSetupconfigured ONCE at startup — never per-request- Middleware ordering: ErrorHandler → Auth → Guards → business logic (see
noony-middleware-ordering) - Use simple permissions for most cases — wildcards add matching overhead
- Permission naming convention:
resource:action(e.g.,posts:create,admin:*) - 403 Forbidden returned when authenticated but lacking permissions (see
noony-error-handling)
Anti-patterns
- ❌ Guards before
AuthenticationMiddleware—context.usernot populated yet, always fails - ❌
GuardSetup.production()inside request handler — initialization latency per request - ❌ Complex wildcard expressions when simple permissions suffice — unnecessary overhead
- ❌ Hardcoding role checks in handler body instead of using guards — scatters authorization logic
- ❌ Same permissions for all endpoints — no granularity, defeats purpose of RBAC
- ❌ Inconsistent permission naming (
admin-readvsadmin:read) — wildcards won't match dashes - ❌ Ownership guards without path parameter extraction —
context.req.paramsis empty
Done when
- You know the difference between authentication (who) and authorization (what)
- Guards placed after
AuthenticationMiddlewarein the pipeline - Path parameters available before ownership guards
- Simple permission checks working with
requirePermissions() - You understand the three protection methods and when to use each
If you need more detail
→ references/guard-patterns.md — GuardSetup presets, three protection methods with code, RBAC patterns, ownership/team-based access, multi-route setup, testing guards, common gotchas