cxxmcp 1.1.6
C++ MCP SDK
Loading...
Searching...
No Matches
auth.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 [caomengxuan666]
2
3#pragma once
4
5#include <cctype>
6#include <optional>
7#include <string>
8#include <string_view>
9#include <unordered_map>
10#include <utility>
11#include <vector>
12
15
18
19namespace mcp::server {
20
21namespace detail {
22
23inline bool ascii_iequals(std::string_view lhs, std::string_view rhs) {
24 if (lhs.size() != rhs.size()) {
25 return false;
26 }
27 for (std::size_t index = 0; index < lhs.size(); ++index) {
28 const auto left = static_cast<unsigned char>(lhs[index]);
29 const auto right = static_cast<unsigned char>(rhs[index]);
30 if (std::tolower(left) != std::tolower(right)) {
31 return false;
32 }
33 }
34 return true;
35}
36
37inline bool constant_time_string_equal(std::string_view lhs,
38 std::string_view rhs) {
39 const auto max_size = lhs.size() > rhs.size() ? lhs.size() : rhs.size();
40 unsigned char diff = static_cast<unsigned char>(lhs.size() ^ rhs.size());
41 for (std::size_t index = 0; index < max_size; ++index) {
42 const auto left =
43 index < lhs.size() ? static_cast<unsigned char>(lhs[index]) : 0;
44 const auto right =
45 index < rhs.size() ? static_cast<unsigned char>(rhs[index]) : 0;
46 diff = static_cast<unsigned char>(diff | (left ^ right));
47 }
48 return diff == 0;
49}
50
51inline std::string_view trim_ascii(std::string_view value) {
52 while (!value.empty() &&
53 std::isspace(static_cast<unsigned char>(value.front())) != 0) {
54 value.remove_prefix(1);
55 }
56 while (!value.empty() &&
57 std::isspace(static_cast<unsigned char>(value.back())) != 0) {
58 value.remove_suffix(1);
59 }
60 return value;
61}
62
63inline std::string_view bearer_token_from_authorization(
64 std::string_view authorization) {
65 authorization = trim_ascii(authorization);
66 constexpr std::string_view kBearer = "Bearer";
67 if (authorization.size() <= kBearer.size() ||
68 !ascii_iequals(authorization.substr(0, kBearer.size()), kBearer) ||
69 std::isspace(static_cast<unsigned char>(authorization[kBearer.size()])) ==
70 0) {
71 return {};
72 }
73 authorization.remove_prefix(kBearer.size());
74 authorization = trim_ascii(authorization);
75 return authorization;
76}
77
78} // namespace detail
79
81inline constexpr std::string_view AuthErrorCategory = "auth";
82
84inline constexpr std::string_view DefaultAuthChallenge = "Bearer";
85
93 std::unordered_map<std::string, std::string> headers;
95 std::string remote_address;
97 std::optional<std::string> http_method;
99 std::optional<std::string> http_url;
100};
101
106 std::string subject;
108 std::unordered_map<std::string, std::string> claims;
109};
110
118 public:
119 virtual ~AuthProvider() = default;
120
128 const AuthRequest& request) = 0;
129};
130
132inline core::Error make_auth_error(std::string message,
133 std::string detail = {}) {
134 return core::Error{
135 static_cast<int>(protocol::ErrorCode::PermissionDenied),
136 std::move(message),
137 std::move(detail),
138 std::string(AuthErrorCategory),
139 };
140}
141
150 public:
151 struct Entry {
152 std::string token;
153 AuthIdentity identity;
154 };
155
156 StaticBearerAuthProvider() = default;
157 explicit StaticBearerAuthProvider(std::vector<Entry> entries)
158 : entries_(std::move(entries)) {}
159
160 void add_token(std::string token, AuthIdentity identity) {
161 entries_.push_back(Entry{std::move(token), std::move(identity)});
162 }
163
165 const auto token = bearer_token(request);
166 if (token.empty()) {
167 return mcp::core::unexpected(
168 make_auth_error("missing or invalid bearer token"));
169 }
170
171 for (const auto& entry : entries_) {
172 if (detail::constant_time_string_equal(token, entry.token)) {
173 return entry.identity;
174 }
175 }
176 return mcp::core::unexpected(
177 make_auth_error("missing or invalid bearer token"));
178 }
179
180 private:
181 static std::string_view bearer_token(const AuthRequest& request) {
182 for (const auto& header : request.headers) {
183 if (detail::ascii_iequals(header.first, "Authorization")) {
184 return detail::bearer_token_from_authorization(header.second);
185 }
186 }
187 return {};
188 }
189
190 std::vector<Entry> entries_;
191};
192
193} // namespace mcp::server
Abstract authentication provider used by server integrations.
Definition auth.hpp:117
virtual core::Result< AuthIdentity > authenticate(const AuthRequest &request)=0
Authenticate a transport request.
Static bearer-token AuthProvider for small embedded deployments and tests.
Definition auth.hpp:149
core::Result< AuthIdentity > authenticate(const AuthRequest &request) override
Authenticate a transport request.
Definition auth.hpp:164
bool constant_time_string_equal(std::string_view lhs, std::string_view rhs) noexcept
Compare two strings without data-dependent early exit.
Definition constant_time.hpp:17
Shared JSON, JSON-RPC, error, cancellation, and progress model types.
Shared result and error primitives used by the public cxxmcp SDK.
tl::expected< T, Error > Result
Alias for the SDK result type.
Definition result.hpp:64
constexpr std::string_view DefaultAuthChallenge
Default HTTP challenge used when a transport has no custom policy.
Definition auth.hpp:84
core::Error make_auth_error(std::string message, std::string detail={})
Build a structured authentication failure for transports.
Definition auth.hpp:132
Structured error returned by fallible SDK operations.
Definition result.hpp:35
Authenticated principal and associated claims.
Definition auth.hpp:103
std::string subject
Stable principal identifier, such as a user id, service account, or token subject.
Definition auth.hpp:106
std::unordered_map< std::string, std::string > claims
Provider-specific claims copied by value into the identity.
Definition auth.hpp:108
Transport-neutral authentication input.
Definition auth.hpp:91
std::string remote_address
Best-effort remote address for audit and policy decisions.
Definition auth.hpp:95
std::unordered_map< std::string, std::string > headers
Request headers or metadata supplied by the transport.
Definition auth.hpp:93
std::optional< std::string > http_url
Absolute HTTP request URL when supplied by an HTTP-based transport.
Definition auth.hpp:99
std::optional< std::string > http_method
HTTP request method when supplied by an HTTP-based transport.
Definition auth.hpp:97