extractRouteCallable($handler); if ($callable === null) { // If no callable is available, delegate to the next handler. return $handler->handle($request); } /** @var Controller $class Controller instance resolved from the route. */ [$class, $method] = $callable; // Ensure the controller exists and the method is defined before reflecting. if (class_exists($class::class)) { $reflectionClass = new \ReflectionClass($class); if ($reflectionClass->hasMethod($method)) { $reflectionMethod = $reflectionClass->getMethod($method); // Fetch all Scope attributes declared on the method. $attributes = $reflectionMethod->getAttributes(Scope::class); foreach ($attributes as $attribute) { /** @var Scope $scopeInstance Concrete Scope attribute instance. */ $scopeInstance = $attribute->newInstance(); $requiredScopes = $scopeInstance->getScopes(); // Retrieve user scopes from the request (defaults to an empty array). $userScopes = $request->getAttribute('scopes', []); // Deny if any required scope is missing from the user's scopes. if ( array_any( $requiredScopes, fn($requiredScope) => !in_array($requiredScope, $userScopes, true) ) ) { return JsonResponseFactory::createJsonResponse([ 'error' => 'insufficient_scope', 'error_description' => 'The request requires higher privileges than provided by the access token.' ], CodesEnum::FORBIDDEN); } } } } // All checks passed; continue down the middleware pipeline. return $handler->handle($request); } }