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