rust_mcp_sdk/auth/auth_provider.rs
1mod remote_auth_provider;
2use crate::auth::OauthEndpoint;
3use crate::auth::{AuthInfo, AuthenticationError};
4use crate::mcp_http::{GenericBody, GenericBodyExt, McpAppState};
5use crate::mcp_server::error::TransportServerError;
6use async_trait::async_trait;
7use http::Method;
8pub use remote_auth_provider::*;
9use std::collections::HashMap;
10use std::sync::Arc;
11
12#[async_trait]
13pub trait AuthProvider: Send + Sync {
14 async fn verify_token(&self, access_token: String) -> Result<AuthInfo, AuthenticationError>;
15
16 /// Returns an optional list of scopes required to access this resource.
17 /// If this function returns `Some(scopes)`, the authenticated user’s token
18 /// must include **all** of the listed scopes.
19 /// If any are missing, the request will be rejected with a `403 Forbidden` response.
20 fn required_scopes(&self) -> Option<&Vec<String>> {
21 None
22 }
23
24 /// Returns the configured OAuth endpoints for this provider.
25 ///
26 /// - Key: endpoint path as a string (e.g., "/oauth/token")
27 /// - Value: corresponding `OauthEndpoint` configuration
28 ///
29 /// Returns `None` if no endpoints are configured.
30 fn auth_endpoints(&self) -> Option<&HashMap<String, OauthEndpoint>>;
31
32 /// Handles an incoming HTTP request for this authentication provider.
33 ///
34 /// This is the main entry point for processing OAuth requests,
35 /// such as token issuance, authorization code exchange, or revocation.
36 async fn handle_request(
37 &self,
38 request: http::Request<&str>,
39 state: Arc<McpAppState>,
40 ) -> Result<http::Response<GenericBody>, TransportServerError>;
41
42 /// Returns the `OauthEndpoint` associated with the given request path.
43 ///
44 /// This method looks up the request URI path in the endpoints returned by `auth_endpoints()`.
45 ///
46 /// ⚠️ Note:
47 /// - If your token and revocation endpoints share the same URL path (valid in some implementations),
48 /// you may want to override this method to correctly distinguish the request type
49 /// (e.g., based on request parameters like `grant_type` vs `token`).
50 fn endpoint_type(&self, request: &http::Request<&str>) -> Option<&OauthEndpoint> {
51 let endpoints = self.auth_endpoints()?;
52 endpoints.get(request.uri().path())
53 }
54
55 /// Returns the absolute URL of this resource's OAuth 2.0 Protected Resource Metadata document.
56 ///
57 /// This corresponds to the `resource_metadata` parameter defined in
58 /// [RFC 9531 - OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9531).
59 ///
60 /// The returned URL is an **absolute** URL (including scheme and host), for example:
61 /// `https://api.example.com/.well-known/oauth-protected-resource`.
62 ///
63 fn protected_resource_metadata_url(&self) -> Option<&str>;
64
65 fn validate_allowed_methods(
66 &self,
67 endpoint: &OauthEndpoint,
68 method: &Method,
69 ) -> Option<http::Response<GenericBody>> {
70 let allowed_methods = match endpoint {
71 OauthEndpoint::AuthorizationEndpoint => {
72 vec![Method::GET, Method::HEAD, Method::OPTIONS]
73 }
74 OauthEndpoint::TokenEndpoint => vec![Method::POST, Method::OPTIONS],
75 OauthEndpoint::RegistrationEndpoint => vec![
76 Method::POST,
77 Method::GET,
78 Method::PUT,
79 Method::PATCH,
80 Method::DELETE,
81 Method::OPTIONS,
82 ],
83 OauthEndpoint::RevocationEndpoint => vec![Method::POST, Method::OPTIONS],
84 OauthEndpoint::IntrospectionEndpoint => vec![Method::POST, Method::OPTIONS],
85 OauthEndpoint::AuthorizationServerMetadata => {
86 vec![Method::GET, Method::HEAD, Method::OPTIONS]
87 }
88 OauthEndpoint::ProtectedResourceMetadata => {
89 vec![Method::GET, Method::HEAD, Method::OPTIONS]
90 }
91 };
92
93 if !allowed_methods.contains(method) {
94 return Some(GenericBody::create_405_response(method, &allowed_methods));
95 }
96 None
97 }
98}