Skip to content

Commit b0afeee

Browse files
committed
feat(gateway): accept API keys in inbound auth middleware
Phase 1. The auth chokepoint now resolves an identity from a valid JWT OR a valid API key (host-issued, validated via the inbound-client repo): when there is no valid JWT, a Bearer that matches a live key resolves to that key's client_id. Falls through to 401 (auth on) / anonymous (auth off) exactly as before. Lets headless/remote clients authenticate without the host-only OAuth consent deep link. Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
1 parent 3640dea commit b0afeee

1 file changed

Lines changed: 32 additions & 6 deletions

File tree

crates/mcpmux-gateway/src/mcp/oauth_middleware.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,45 @@ pub async fn mcp_oauth_middleware(
9595
None => None,
9696
};
9797

98-
// Resolve (client_id, space_id) from the token, or — when auth is disabled
99-
// — fall back to an anonymous identity on the default space.
100-
let (client_id, space_id) = if let Some(claims) = claims {
98+
// If there's no valid JWT, a presented Bearer may instead be a long-lived
99+
// API key (host-issued, for headless/remote clients) — validate it directly
100+
// to a client_id so a remote client can authenticate with no interactive
101+
// consent (the OAuth consent deep link only works on the host).
102+
let api_key_client_id = if claims.is_none() {
103+
match token {
104+
Some(tok) => match services
105+
.dependencies
106+
.inbound_client_repo
107+
.validate_api_key(tok)
108+
.await
109+
{
110+
Ok(result) => result.map(|auth| auth.client_id),
111+
Err(e) => {
112+
warn!(trace_id = %trace_id, "API key validation error: {}", e);
113+
None
114+
}
115+
},
116+
None => None,
117+
}
118+
} else {
119+
None
120+
};
121+
122+
// Resolve (client_id, space_id) from the authenticated identity (JWT or API
123+
// key); when auth is disabled, fall back to an anonymous identity on the
124+
// default space.
125+
let authed_client_id = claims.map(|c| c.client_id).or(api_key_client_id);
126+
let (client_id, space_id) = if let Some(cid) = authed_client_id {
101127
match services
102128
.space_resolver_service
103-
.resolve_space_for_client(&claims.client_id)
129+
.resolve_space_for_client(&cid)
104130
.await
105131
{
106-
Ok(id) => (claims.client_id, id),
132+
Ok(id) => (cid, id),
107133
Err(e) => {
108134
warn!(
109135
trace_id = %trace_id,
110-
client_id = %claims.client_id,
136+
client_id = %cid,
111137
"Failed to resolve space: {}", e
112138
);
113139
return (

0 commit comments

Comments
 (0)