@@ -123,6 +123,102 @@ Notes:
123123- Client parsing: handled in [ src/mcp/Client.cpp] ( ../../src/mcp/Client.cpp ) ` parseServerCapabilities() ` .
124124- Tests: [ tests/test_capabilities_logging.cpp] ( ../../tests/test_capabilities_logging.cpp ) .
125125
126+ ## Server-side Bearer authentication (HTTP acceptor)
127+
128+ Header: [ include/mcp/auth/ServerAuth.hpp] ( ../../include/mcp/auth/ServerAuth.hpp )
129+
130+ The HTTP server acceptor can enforce Bearer authentication for incoming POSTs to ` rpcPath ` and ` notifyPath ` when explicitly enabled.
131+
132+ - API
133+ - ` void HTTPServer::SetBearerAuth(mcp::auth::ITokenVerifier& verifier, const mcp::auth::RequireBearerTokenOptions& opts) `
134+ - ` mcp::auth::ITokenVerifier ` verifies the bearer token and populates ` TokenInfo ` (scopes, expiration, extra).
135+ - ` mcp::auth::RequireBearerTokenOptions ` controls enforcement:
136+ - ` resourceMetadataUrl ` : included in ` WWW-Authenticate: Bearer resource_metadata=<url> ` on 401/403.
137+ - ` requiredScopes ` : all listed scopes must be present; otherwise 403.
138+
139+ - Behavior
140+ - Authorization header must be ` Authorization: Bearer <token> ` (scheme case-insensitive).
141+ - On missing/invalid token → 401 Unauthorized.
142+ - On missing expiration or expired token → 401 Unauthorized.
143+ - On insufficient scope → 403 Forbidden.
144+ - When ` resourceMetadataUrl ` is provided, responses include ` WWW-Authenticate: Bearer resource_metadata=<url> ` .
145+ - On success, the verified token is available during handler execution via ` mcp::auth::currentTokenInfo() ` .
146+ - When ` SetBearerAuth(...) ` is not called, no authentication is enforced (backward compatible).
147+
148+ - Example (bridge to Server::HandleJSONRPC)
149+
150+ ``` cpp
151+ #include " mcp/HTTPServer.hpp"
152+ #include " mcp/Server.h"
153+ #include " mcp/auth/ServerAuth.hpp"
154+
155+ mcp::ServerFactory sf;
156+ auto server = sf.CreateServer({"Demo","1.0.0"});
157+
158+ mcp::HTTPServerFactory hf;
159+ auto acceptor = hf.CreateTransportAcceptor("http://127.0.0.1:9443 ");
160+
161+ struct MyVerifier : mcp::auth::ITokenVerifier {
162+ bool Verify(const std::string& token, mcp::auth::TokenInfo& out, std::string& err) override {
163+ if (token != "demo") { err = "invalid token"; return false; }
164+ out.scopes = {"tools: invoke "};
165+ out.expiration = std::chrono::system_clock::now() + std::chrono::minutes(5);
166+ return true;
167+ }
168+ } verifier;
169+
170+ mcp::auth::RequireBearerTokenOptions opts;
171+ opts.resourceMetadataUrl = " https://auth.example.com/rs" ;
172+ opts.requiredScopes = {"tools: invoke "};
173+
174+ auto* http = dynamic_cast< mcp::HTTPServer* > (acceptor.get());
175+ if (http) { http->SetBearerAuth(verifier, opts); }
176+
177+ acceptor->SetRequestHandler([ &server] (const mcp::JSONRPCRequest& req){ return server->HandleJSONRPC(req); });
178+ acceptor->Start().get();
179+ ```
180+
181+ - Accessing token info in handlers
182+ - Inside server/tool handlers, use `mcp::auth::currentTokenInfo()` to read the request’s token metadata.
183+
184+ - Demo (run_demo.sh)
185+ - The demo wiring supports environment toggles to exercise this flow end-to-end:
186+ - `MCP_HTTP_REQUIRE_BEARER=1` — enable server-side Bearer for the HTTP demo.
187+ - `MCP_HTTP_RESOURCE_METADATA_URL=https://auth.example.com/rs` — advertised in `WWW-Authenticate`.
188+ - `MCP_HTTP_DEMO_TOKEN=demo` — client token to accept (demo verifier).
189+ - `MCP_HTTP_DEMO_SCOPES=s1,s2` — scopes attached by the demo verifier (default `s1,s2`).
190+ - `MCP_HTTP_REQUIRED_SCOPES=s1` — required scopes to enforce (optional).
191+ - The CTest target `HTTPDemo.BearerAuth` first verifies an unauthorized probe (expects 401 + `WWW-Authenticate`) and then runs the client with a bearer token to observe a successful 200 path.
192+
193+ ### Flow (ASCII)
194+
195+ ```
196+ +---------+ +------------------+
197+ | Client | | HTTPServer |
198+ +---------+ +------------------+
199+ | POST /mcp/rpc (no Authorization) |
200+ |---------------------------------------------------------->|
201+ | |
202+ |<----------------------------------------------------------|
203+ | 401 Unauthorized |
204+ | WWW-Authenticate: Bearer resource_metadata=<url > |
205+ | |
206+ | POST /mcp/rpc |
207+ |(Authorization: Bearer <token with bad scope >) |
208+ |---------------------------------------------------------->|
209+ | |
210+ |<----------------------------------------------------------|
211+ | 403 Forbidden |
212+ | WWW-Authenticate: Bearer resource_metadata=<url > |
213+ | |
214+ | POST /mcp/rpc |
215+ |(Authorization: Bearer <valid token >) |
216+ |---------------------------------------------------------->|
217+ | |
218+ |<----------------------------------------------------------|
219+ | 200 OK (JSON-RPC response) |
220+ ```
221+
126222## Tools
127223- void RegisterTool(const std::string& name, ToolHandler handler)
128224- void RegisterTool(const Tool& tool, ToolHandler handler)
0 commit comments