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