authenticateByApiKey($request); // Fall back to session auth if (! $workspace && $request->user()) { $user = $request->user(); if (method_exists($user, 'defaultHostWorkspace')) { $workspace = $user->defaultHostWorkspace(); } } // Store workspace for downstream use if ($workspace) { $request->attributes->set('mcp_workspace', $workspace); // Check MCP access entitlement $result = $this->entitlementService->can($workspace, 'mcp.access'); $request->attributes->set('mcp_entitlement', $result); } // For 'required' level, must have workspace if ($level === 'required' && ! $workspace) { return $this->unauthenticatedResponse($request); } return $next($request); } /** * Authenticate using API key from header or query. */ protected function authenticateByApiKey(Request $request): ?Workspace { $apiKey = $request->header('X-API-Key') ?? $request->header('Authorization') ?? $request->query('api_key'); if (! $apiKey) { return null; } // Strip 'Bearer ' prefix if present if (str_starts_with($apiKey, 'Bearer ')) { $apiKey = substr($apiKey, 7); } // Look up workspace by API key return Workspace::whereHas('apiKeys', function ($query) use ($apiKey) { $query->where('key', hash('sha256', $apiKey)) ->where(function ($q) { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }); })->first(); } /** * Return unauthenticated response. */ protected function unauthenticatedResponse(Request $request): Response { if ($request->expectsJson() || $request->is('api/*')) { return response()->json([ 'error' => 'unauthenticated', 'message' => 'Authentication required. Provide an API key or sign in.', ], 401); } return redirect()->guest(route('login')); } }