extractBearerToken($request); if ($token !== null) { try { $claims = $this->jwt->decode($token); $userId = (string) ($claims->sub ?? ''); if ($userId !== '') { $user = $this->users->findById($userId); if ($user !== null) { $request->attributes->set('actor_user', $user); $request->attributes->set('actor_user_id', $userId); $request->attributes->set('actor_session_id', (string) ($claims->sid ?? 'bypass-jwt')); $request->attributes->set('actor_roles', $this->rbac->rolesForUser($userId)); $request->attributes->set('actor_permissions', $this->rbac->permissionsForUser($userId)); return $next($request); } } } catch (Throwable) { // Invalid JWT — fall through to bypass actor } } $bypass = DB::table('users')->whereNull('deleted_at')->orderBy('id')->first(); $userId = $bypass !== null ? (string) $bypass->id : 'staging-bypass'; $request->attributes->set('actor_user', $bypass); $request->attributes->set('actor_user_id', $userId); $request->attributes->set('actor_session_id', 'bypass'); $request->attributes->set('actor_roles', $bypass !== null ? $this->rbac->rolesForUser($userId) : ['SUPER_ADMIN']); $request->attributes->set('actor_permissions', $bypass !== null ? $this->rbac->permissionsForUser($userId) : ['SUPER_ADMIN_ACCESS']); return $next($request); } $token = $this->extractBearerToken($request); if ($token === null) { return ApiResponse::error('UNAUTHORIZED', 'Authentication is required.', [], 401); } try { $claims = $this->jwt->decode($token); } catch (Throwable) { return ApiResponse::error('UNAUTHORIZED', 'Authentication token is invalid or expired.', [], 401); } $userId = (string) ($claims->sub ?? ''); $sessionId = (string) ($claims->sid ?? ''); $user = $this->users->findById($userId); $session = $this->sessions->findActiveById($sessionId); if ($user === null || $session === null || $session->user_id !== $userId) { return ApiResponse::error('UNAUTHORIZED', 'Authentication token is invalid or expired.', [], 401); } if ($user->disabled_at !== null || $user->user_status === 'DISABLED') { return ApiResponse::error('USER_DISABLED', 'This user account is disabled.', [], 403); } if (in_array(strtoupper((string) ($user->portal_status ?? '')), ['SUSPENDED', 'DISABLED'], true)) { return ApiResponse::error('PORTAL_ACCESS_DISABLED', 'This portal account is not active.', [], 403); } $request->attributes->set('actor_user', $user); $request->attributes->set('actor_user_id', $userId); $request->attributes->set('actor_session_id', $sessionId); $request->attributes->set('actor_roles', $this->rbac->rolesForUser($userId)); $request->attributes->set('actor_permissions', $this->rbac->permissionsForUser($userId)); return $next($request); } private function extractBearerToken(Request $request): ?string { $candidates = [ $request->headers->get('X-Authorization'), $request->headers->get('Authorization'), $request->server('HTTP_X_AUTHORIZATION'), $request->server('HTTP_AUTHORIZATION'), $request->server('REDIRECT_HTTP_AUTHORIZATION'), $request->server('Authorization'), $_SERVER['HTTP_X_AUTHORIZATION'] ?? null, $_SERVER['HTTP_AUTHORIZATION'] ?? null, $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? null, $_SERVER['Authorization'] ?? null, ]; if (function_exists('getallheaders')) { $headers = getallheaders(); $candidates[] = $headers['X-Authorization'] ?? $headers['x-authorization'] ?? null; $candidates[] = $headers['Authorization'] ?? $headers['authorization'] ?? null; } if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); $candidates[] = $headers['X-Authorization'] ?? $headers['x-authorization'] ?? null; $candidates[] = $headers['Authorization'] ?? $headers['authorization'] ?? null; } foreach ($candidates as $candidate) { $value = trim((string) ($candidate ?? '')); if ($value === '') { continue; } if (preg_match('/^Bearer\s+(.+)$/i', $value, $matches) === 1) { $token = trim($matches[1]); if ($token !== '') { return $token; } } if (preg_match('/^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$/', $value) === 1) { return $value; } } return null; } }