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