{"record":{"id":"14d94211945b9edc","repo":"affaan-m/ECC","slug":"unauthorized-this-area-requires-role","errorCode":null,"errorMessage":"Unauthorized. This area requires role: ","messagePattern":"Unauthorized\\. This area requires role: ","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"skills/laravel-security/SKILL.md","lineNumber":316,"sourceCode":"\n### Middleware Authorization\n\n```php\n// Using middleware in routes\nRoute::put('/posts/{post}', [PostController::class, 'update'])\n    ->middleware('can:update,post');\n\nRoute::get('/posts/create', [PostController::class, 'create'])\n    ->middleware('can:create,App\\Models\\Post');\n\n// Custom authorization middleware\n// app/Http/Middleware/CheckRole.php\nclass CheckRole\n{\n    public function handle(Request $request, Closure $next, string $role): mixed\n    {\n        if (!$request->user() || $request->user()->role !== $role) {\n            abort(403, 'Unauthorized. This area requires role: ' . $role);\n        }\n        return $next($request);\n    }\n}\n\n// Register in Kernel\nprotected $routeMiddleware = [\n    'role' => \\App\\Http\\Middleware\\CheckRole::class,\n];\n\n// Route usage\nRoute::middleware(['auth', 'role:admin'])->group(function () {\n    Route::get('/admin', [AdminController::class, 'index']);\n});\n```\n\n## Eloquent Security\n","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/laravel-security/SKILL.md#L298-L334","documentation":"Laravel's abort(403, ...) triggered by a custom CheckRole middleware when the authenticated user's role does not match the route's required role, or when no user is authenticated at all. The middleware runs on every request through the 'role' route middleware alias and short-circuits the request with a 403 response.","triggerScenarios":"A route guarded by ->middleware(['auth','role:admin']) receives a request from a user whose ->role attribute is not 'admin', or an unauthenticated request that slipped past the 'auth' middleware. The comparison is strict string inequality against the route parameter.","commonSituations":"User record has a role stored with different casing ('Admin' vs 'admin'); role stored in a separate roles table (many-to-many) but the User model exposes only a single ->role attribute; 'auth' middleware not applied so $request->user() is null; route middleware registration order wrong.","solutions":["Confirm the 'auth' middleware runs before 'role' so $request->user() is populated.","Normalize role comparison (lowercase/trim) and consider role hierarchy (e.g. editor implies viewer).","If roles are many-to-many, replace the single-role check with $user->hasRole($role) using a relationship.","Register the 'role' alias in app/Http/Kernel.php (or bootstrap/app.php on Laravel 11+) before referencing it in routes.","Return a JSON 403 for API routes instead of abort()'s default HTML."],"exampleFix":"// before\nif (!$request->user() || $request->user()->role !== $role) {\n    abort(403, 'Unauthorized. This area requires role: ' . $role);\n}\n\n// after: null-safe, case-insensitive, supports many-to-many roles\n$user = $request->user();\nif (!$user || ! $user->hasRole($role)) {\n    abort(403, \"This area requires role: {$role}\");\n}","handlingStrategy":"validation","validationCode":"// gate sensitive actions behind a policy/policy-check before the route runs\nGate::authorize('admin-only');\n// or use Laravel policies + can: middleware instead of a custom CheckRole","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Prefer Laravel policies and the can: middleware over hand-rolled role checks.","Normalize roles to lowercase and consider a role hierarchy.","Ensure 'auth' runs before 'role' in the middleware stack.","Register the 'role' alias in the kernel/bootstrap."],"tags":["php","laravel","authorization","middleware","rbac"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}