Skip to main content

github_mcp/http/
auth_extractor.rs

1// GitHub v3 REST API MCP server — generated by mcpify. Do not hand-edit.
2
3use axum::http::HeaderMap;
4
5use crate::auth::request_credentials::RequestCredentials;
6
7#[derive(Debug, PartialEq)]
8pub enum ExtractError {
9    /// The header this auth method needs wasn't present (or was empty).
10    Missing,
11    /// The auth method's declared location can't be relayed over HTTP
12    /// transport at all — only `"header"` locations can (query/cookie
13    /// schemes, and OAuth1's `"none"`, are rejected here).
14    UnsupportedLocation(String),
15}
16
17/// Extracts the credential value for the active auth method's declared
18/// location (`AuthManager::header_location`/`header_location_for`) off an
19/// incoming HTTP request. The extracted value is relayed verbatim to the
20/// facaded API — whatever the caller sent, prefixed or not.
21pub fn extract_request_credentials(
22    headers: &HeaderMap,
23    header_location: &str,
24    header_name: &str,
25) -> Result<RequestCredentials, ExtractError> {
26    if header_location != "header" {
27        return Err(ExtractError::UnsupportedLocation(
28            header_location.to_string(),
29        ));
30    }
31
32    let value = headers
33        .get(header_name)
34        .and_then(|value| value.to_str().ok())
35        .filter(|value| !value.is_empty())
36        .ok_or(ExtractError::Missing)?;
37
38    Ok(RequestCredentials {
39        header_name: header_name.to_string(),
40        value: value.to_string(),
41    })
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn extracts_a_present_header() {
50        let mut headers = HeaderMap::new();
51        headers.insert("Authorization", "Bearer abc".parse().unwrap());
52        let creds = extract_request_credentials(&headers, "header", "Authorization").unwrap();
53        assert_eq!(creds.header_name, "Authorization");
54        assert_eq!(creds.value, "Bearer abc");
55    }
56
57    #[test]
58    fn errors_when_the_header_is_absent() {
59        let headers = HeaderMap::new();
60        assert_eq!(
61            extract_request_credentials(&headers, "header", "Authorization"),
62            Err(ExtractError::Missing)
63        );
64    }
65
66    #[test]
67    fn errors_when_the_header_is_present_but_empty() {
68        let mut headers = HeaderMap::new();
69        headers.insert("X-Api-Key", "".parse().unwrap());
70        assert_eq!(
71            extract_request_credentials(&headers, "header", "X-Api-Key"),
72            Err(ExtractError::Missing)
73        );
74    }
75
76    #[test]
77    fn rejects_query_and_cookie_locations() {
78        let headers = HeaderMap::new();
79        assert_eq!(
80            extract_request_credentials(&headers, "query", "api_key"),
81            Err(ExtractError::UnsupportedLocation("query".to_string()))
82        );
83        assert_eq!(
84            extract_request_credentials(&headers, "cookie", "session"),
85            Err(ExtractError::UnsupportedLocation("cookie".to_string()))
86        );
87        assert_eq!(
88            extract_request_credentials(&headers, "none", ""),
89            Err(ExtractError::UnsupportedLocation("none".to_string()))
90        );
91    }
92}