use turbomcp_auth::server::{
BearerTokenValidator, ProtectedResourceMetadataBuilder, WwwAuthenticateBuilder,
unauthorized_response_body,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Protected Resource Server Example ===\n");
println!("1. Protected Resource Metadata (/.well-known/protected-resource):");
let metadata = ProtectedResourceMetadataBuilder::new(
"https://mcp.example.com".to_string(),
"https://auth.example.com/.well-known/oauth-authorization-server".to_string(),
)
.with_scopes(vec![
"mcp:read".to_string(),
"mcp:write".to_string(),
"openid".to_string(),
])
.with_documentation("https://mcp.example.com/docs".to_string())
.build();
println!("{}\n", serde_json::to_string_pretty(&metadata)?);
println!("2. Handling 401 Unauthorized Response:");
println!(" Status: 401 Unauthorized");
let www_authenticate = WwwAuthenticateBuilder::new(
"https://mcp.example.com/.well-known/protected-resource".to_string(),
)
.with_scope("mcp:read mcp:write".to_string())
.build();
println!(" Header: WWW-Authenticate: {}\n", www_authenticate);
let error_body = unauthorized_response_body(
"https://mcp.example.com/.well-known/protected-resource",
Some("mcp:read"),
);
println!(" Body: {}\n", serde_json::to_string_pretty(&error_body)?);
println!("3. Bearer Token Validation:");
let examples = vec![
("Bearer valid_token_123", true),
("bearer valid_token_456", true), ("invalid_format", false),
("Bearer ", false),
];
for (header, should_succeed) in examples {
let result = BearerTokenValidator::extract_from_header(header);
let status = if result.is_ok() == should_succeed {
"✓"
} else {
"✗"
};
println!(
" {} {} => {:?}",
status,
header,
result
.map(|t| format!("token: {}", t))
.unwrap_or_else(|e| format!("error: {}", e))
);
}
println!("\n4. Token Format Validation:");
let tokens = vec![
("", false, "empty"),
("123", false, "too short"),
("valid_token_12345", true, "valid"),
];
for (token, should_succeed, desc) in tokens {
let result = BearerTokenValidator::validate_format(token);
let status = if result.is_ok() == should_succeed {
"✓"
} else {
"✗"
};
println!(" {} {} => {:?}", status, desc, result);
}
println!("\n5. OAuth2 Authorization Flow:");
println!(" Client: Initiates OAuth2 Authorization Code flow");
println!(" User: Grants permissions");
println!(" Server: Receives access token");
println!(" Server: Validates token and returns protected resource");
println!("\n6. Typical Request/Response Pattern:");
println!("\n Request 1 (no token):");
println!(" GET /api/resource");
println!(" --> 401 Unauthorized");
println!(" --> WWW-Authenticate: Bearer resource_metadata=\"...\"");
println!("\n Request 2 (after getting token):");
println!(" GET /api/resource");
println!(" Authorization: Bearer access_token_xyz");
println!(" --> 200 OK");
println!(" --> {{\"data\": \"protected_resource_data\"}}");
println!("\n7. Recommended Server Implementation:");
println!(" a. Implement /.well-known/protected-resource endpoint");
println!(" Returns: ProtectedResourceMetadataBuilder::new(...).build()");
println!();
println!(" b. Implement Bearer token extraction middleware");
println!(" Use: BearerTokenValidator::extract_from_header()");
println!();
println!(" c. Implement token validation");
println!(" - Call OAuth2 provider's introspection endpoint");
println!(" - Check token scopes against required scopes");
println!(" - Verify token not expired");
println!();
println!(" d. Return 401 with WWW-Authenticate on invalid token");
println!(" Use: WwwAuthenticateBuilder::new(metadata_uri).build()");
Ok(())
}