Skip to main content

tuwunel_api/oidc/
auth_metadata.rs

1use axum::{Json, extract::State, response::IntoResponse};
2use serde::{Deserialize, Serialize};
3use tuwunel_core::Result;
4
5use super::ACCOUNT_MANAGEMENT_ACTIONS_SUPPORTED;
6
7#[derive(Debug, Serialize, Deserialize)]
8struct ProviderMetadata {
9	issuer: String,
10	authorization_endpoint: String,
11	token_endpoint: String,
12	registration_endpoint: Option<String>,
13	revocation_endpoint: Option<String>,
14	jwks_uri: String,
15	userinfo_endpoint: Option<String>,
16	account_management_uri: Option<String>,
17	account_management_actions_supported: Option<Vec<String>>,
18	response_types_supported: Vec<String>,
19	response_modes_supported: Option<Vec<String>>,
20	grant_types_supported: Option<Vec<String>>,
21	code_challenge_methods_supported: Option<Vec<String>>,
22	token_endpoint_auth_methods_supported: Option<Vec<String>>,
23	scopes_supported: Option<Vec<String>>,
24	subject_types_supported: Option<Vec<String>>,
25	id_token_signing_alg_values_supported: Option<Vec<String>>,
26	prompt_values_supported: Option<Vec<String>>,
27	claim_types_supported: Option<Vec<String>>,
28	claims_supported: Option<Vec<String>>,
29}
30
31pub(crate) async fn openid_configuration_route(
32	State(services): State<crate::State>,
33) -> Result<impl IntoResponse> {
34	let issuer = services.oauth.get_server()?.issuer_url()?;
35	let base = issuer.trim_end_matches('/').to_owned();
36
37	Ok(Json(ProviderMetadata {
38		issuer,
39
40		authorization_endpoint: format!("{base}/_tuwunel/oidc/authorize"),
41
42		registration_endpoint: Some(format!("{base}/_tuwunel/oidc/registration")),
43
44		userinfo_endpoint: Some(format!("{base}/_tuwunel/oidc/userinfo")),
45
46		token_endpoint: format!("{base}/_tuwunel/oidc/token"),
47
48		jwks_uri: format!("{base}/_tuwunel/oidc/jwks"),
49
50		account_management_uri: Some(format!("{base}/_tuwunel/oidc/account")),
51
52		revocation_endpoint: Some(format!("{base}/_tuwunel/oidc/revoke")),
53
54		response_modes_supported: Some(vec!["query".to_owned(), "fragment".to_owned()]),
55
56		response_types_supported: vec!["code".to_owned()],
57
58		code_challenge_methods_supported: Some(vec!["S256".to_owned()]),
59
60		id_token_signing_alg_values_supported: Some(vec!["ES256".to_owned()]),
61
62		prompt_values_supported: Some(vec![]),
63
64		subject_types_supported: Some(vec!["public".to_owned()]),
65
66		claim_types_supported: Some(vec!["normal".to_owned()]),
67
68		grant_types_supported: Some(vec![
69			"authorization_code".to_owned(),
70			"refresh_token".to_owned(),
71		]),
72
73		token_endpoint_auth_methods_supported: Some(vec![
74			"none".to_owned(),
75			"client_secret_basic".to_owned(),
76			"client_secret_post".to_owned(),
77		]),
78
79		scopes_supported: Some(vec![
80			"openid".to_owned(),
81			"urn:matrix:org.matrix.msc2967.client:api:*".to_owned(),
82			"urn:matrix:org.matrix.msc2967.client:device:*".to_owned(),
83		]),
84
85		account_management_actions_supported: Some(
86			ACCOUNT_MANAGEMENT_ACTIONS_SUPPORTED
87				.iter()
88				.map(ToString::to_string)
89				.collect(),
90		),
91
92		claims_supported: Some(vec![
93			"iss".to_owned(),
94			"sub".to_owned(),
95			"aud".to_owned(),
96			"exp".to_owned(),
97			"iat".to_owned(),
98			"nonce".to_owned(),
99		]),
100	}))
101}