buildAuthenticatorChain(); } public function processRequest(ServerRequestInterface $request): ServerRequestInterface { // Try each authenticator in order foreach ($this->authenticators as $authenticator) { $user = $authenticator->authenticate($request); if ($user !== null) { return $request->withAttribute('api_user', $user); } } throw new UnauthorizedException( 'No valid authentication credentials provided. Use an API key, JWT token, or active session.' ); } /** * Optimistic authentication for public routes: attach api_user when valid * credentials are supplied, continue as guest otherwise. Lets public * endpoints return richer, permission-filtered responses to logged-in * callers without requiring auth from anonymous ones. */ public function processOptional(ServerRequestInterface $request): ServerRequestInterface { foreach ($this->authenticators as $authenticator) { $user = $authenticator->authenticate($request); if ($user !== null) { return $request->withAttribute('api_user', $user); } } return $request; } protected function buildAuthenticatorChain(): void { // API Key is fastest to check - try first if ($this->config->get('plugins.api.auth.api_keys_enabled', true)) { $this->authenticators[] = new ApiKeyAuthenticator($this->grav); } // JWT is next if ($this->config->get('plugins.api.auth.jwt_enabled', true)) { $this->authenticators[] = new JwtAuthenticator($this->grav, $this->config); } // Session passthrough is last (requires existing session) if ($this->config->get('plugins.api.auth.session_enabled', true)) { $this->authenticators[] = new SessionAuthenticator($this->grav); } } }