this repo has no description
1use axum::{Json, extract::State}; 2use serde::{Deserialize, Serialize}; 3 4use crate::state::AppState; 5use crate::oauth::jwks::{JwkSet, create_jwk_set}; 6 7#[derive(Debug, Serialize, Deserialize)] 8pub struct ProtectedResourceMetadata { 9 pub resource: String, 10 pub authorization_servers: Vec<String>, 11 pub bearer_methods_supported: Vec<String>, 12 pub scopes_supported: Vec<String>, 13 #[serde(skip_serializing_if = "Option::is_none")] 14 pub resource_documentation: Option<String>, 15} 16 17#[derive(Debug, Serialize, Deserialize)] 18pub struct AuthorizationServerMetadata { 19 pub issuer: String, 20 pub authorization_endpoint: String, 21 pub token_endpoint: String, 22 pub jwks_uri: String, 23 #[serde(skip_serializing_if = "Option::is_none")] 24 pub registration_endpoint: Option<String>, 25 #[serde(skip_serializing_if = "Option::is_none")] 26 pub scopes_supported: Option<Vec<String>>, 27 pub response_types_supported: Vec<String>, 28 #[serde(skip_serializing_if = "Option::is_none")] 29 pub response_modes_supported: Option<Vec<String>>, 30 #[serde(skip_serializing_if = "Option::is_none")] 31 pub grant_types_supported: Option<Vec<String>>, 32 #[serde(skip_serializing_if = "Option::is_none")] 33 pub token_endpoint_auth_methods_supported: Option<Vec<String>>, 34 #[serde(skip_serializing_if = "Option::is_none")] 35 pub code_challenge_methods_supported: Option<Vec<String>>, 36 #[serde(skip_serializing_if = "Option::is_none")] 37 pub pushed_authorization_request_endpoint: Option<String>, 38 #[serde(skip_serializing_if = "Option::is_none")] 39 pub require_pushed_authorization_requests: Option<bool>, 40 #[serde(skip_serializing_if = "Option::is_none")] 41 pub dpop_signing_alg_values_supported: Option<Vec<String>>, 42 #[serde(skip_serializing_if = "Option::is_none")] 43 pub authorization_response_iss_parameter_supported: Option<bool>, 44 #[serde(skip_serializing_if = "Option::is_none")] 45 pub revocation_endpoint: Option<String>, 46 #[serde(skip_serializing_if = "Option::is_none")] 47 pub introspection_endpoint: Option<String>, 48} 49 50pub async fn oauth_protected_resource( 51 State(_state): State<AppState>, 52) -> Json<ProtectedResourceMetadata> { 53 let pds_hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string()); 54 let public_url = format!("https://{}", pds_hostname); 55 56 Json(ProtectedResourceMetadata { 57 resource: public_url.clone(), 58 authorization_servers: vec![public_url], 59 bearer_methods_supported: vec!["header".to_string()], 60 scopes_supported: vec![], 61 resource_documentation: Some("https://atproto.com".to_string()), 62 }) 63} 64 65pub async fn oauth_authorization_server( 66 State(_state): State<AppState>, 67) -> Json<AuthorizationServerMetadata> { 68 let pds_hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string()); 69 let issuer = format!("https://{}", pds_hostname); 70 71 Json(AuthorizationServerMetadata { 72 issuer: issuer.clone(), 73 authorization_endpoint: format!("{}/oauth/authorize", issuer), 74 token_endpoint: format!("{}/oauth/token", issuer), 75 jwks_uri: format!("{}/oauth/jwks", issuer), 76 registration_endpoint: None, 77 scopes_supported: Some(vec![ 78 "atproto".to_string(), 79 "transition:generic".to_string(), 80 "transition:chat.bsky".to_string(), 81 ]), 82 response_types_supported: vec!["code".to_string()], 83 response_modes_supported: Some(vec!["query".to_string(), "fragment".to_string()]), 84 grant_types_supported: Some(vec![ 85 "authorization_code".to_string(), 86 "refresh_token".to_string(), 87 ]), 88 token_endpoint_auth_methods_supported: Some(vec![ 89 "none".to_string(), 90 "private_key_jwt".to_string(), 91 ]), 92 code_challenge_methods_supported: Some(vec!["S256".to_string()]), 93 pushed_authorization_request_endpoint: Some(format!("{}/oauth/par", issuer)), 94 require_pushed_authorization_requests: Some(true), 95 dpop_signing_alg_values_supported: Some(vec![ 96 "ES256".to_string(), 97 "ES384".to_string(), 98 "ES512".to_string(), 99 "EdDSA".to_string(), 100 ]), 101 authorization_response_iss_parameter_supported: Some(true), 102 revocation_endpoint: Some(format!("{}/oauth/revoke", issuer)), 103 introspection_endpoint: Some(format!("{}/oauth/introspect", issuer)), 104 }) 105} 106 107pub async fn oauth_jwks(State(_state): State<AppState>) -> Json<JwkSet> { 108 use crate::config::AuthConfig; 109 use crate::oauth::jwks::Jwk; 110 111 let config = AuthConfig::get(); 112 113 let server_key = Jwk { 114 kty: "EC".to_string(), 115 key_use: Some("sig".to_string()), 116 kid: Some(config.signing_key_id.clone()), 117 alg: Some("ES256".to_string()), 118 crv: Some("P-256".to_string()), 119 x: Some(config.signing_key_x.clone()), 120 y: Some(config.signing_key_y.clone()), 121 }; 122 123 Json(create_jwk_set(vec![server_key])) 124}