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	device_authorization_endpoint: Option<String>,
13	registration_endpoint: Option<String>,
14	revocation_endpoint: Option<String>,
15	jwks_uri: String,
16	userinfo_endpoint: Option<String>,
17	account_management_uri: Option<String>,
18	account_management_actions_supported: Option<Vec<String>>,
19	response_types_supported: Vec<String>,
20	response_modes_supported: Option<Vec<String>>,
21	grant_types_supported: Option<Vec<String>>,
22	code_challenge_methods_supported: Option<Vec<String>>,
23	token_endpoint_auth_methods_supported: Option<Vec<String>>,
24	scopes_supported: Option<Vec<String>>,
25	subject_types_supported: Option<Vec<String>>,
26	id_token_signing_alg_values_supported: Option<Vec<String>>,
27	prompt_values_supported: Option<Vec<String>>,
28	claim_types_supported: Option<Vec<String>>,
29	claims_supported: Option<Vec<String>>,
30}
31
32pub(crate) async fn openid_configuration_route(
33	State(services): State<crate::State>,
34) -> Result<impl IntoResponse> {
35	let issuer = services.oauth.get_server()?.issuer_url()?;
36	let base = issuer.trim_end_matches('/').to_owned();
37
38	// MSC2964: advertise `create` only when a client can act on it, i.e. native
39	// auth is serving local registration.
40	let native_registration = services.config.authentication.oidc.native_auth
41		&& services.config.allows_password_registration();
42
43	let prompt_values: Vec<String> = native_registration
44		.then(|| "create".to_owned())
45		.into_iter()
46		.collect();
47
48	Ok(Json(ProviderMetadata {
49		issuer,
50
51		authorization_endpoint: format!("{base}/_tuwunel/oidc/authorize"),
52
53		registration_endpoint: Some(format!("{base}/_tuwunel/oidc/registration")),
54
55		userinfo_endpoint: Some(format!("{base}/_tuwunel/oidc/userinfo")),
56
57		token_endpoint: format!("{base}/_tuwunel/oidc/token"),
58
59		device_authorization_endpoint: Some(format!("{base}/_tuwunel/oidc/device_authorization")),
60
61		jwks_uri: format!("{base}/_tuwunel/oidc/jwks"),
62
63		account_management_uri: Some(format!("{base}/_tuwunel/oidc/account")),
64
65		revocation_endpoint: Some(format!("{base}/_tuwunel/oidc/revoke")),
66
67		response_modes_supported: Some(vec!["query".to_owned(), "fragment".to_owned()]),
68
69		response_types_supported: vec!["code".to_owned()],
70
71		code_challenge_methods_supported: Some(vec!["S256".to_owned()]),
72
73		id_token_signing_alg_values_supported: Some(vec!["ES256".to_owned()]),
74
75		prompt_values_supported: Some(prompt_values),
76
77		subject_types_supported: Some(vec!["public".to_owned()]),
78
79		claim_types_supported: Some(vec!["normal".to_owned()]),
80
81		grant_types_supported: Some(vec![
82			"authorization_code".to_owned(),
83			"refresh_token".to_owned(),
84			"urn:ietf:params:oauth:grant-type:device_code".to_owned(),
85		]),
86
87		token_endpoint_auth_methods_supported: Some(vec![
88			"none".to_owned(),
89			"client_secret_basic".to_owned(),
90			"client_secret_post".to_owned(),
91		]),
92
93		scopes_supported: Some(vec![
94			"openid".to_owned(),
95			"urn:matrix:client:api:*".to_owned(),
96			"urn:matrix:org.matrix.msc2967.client:api:*".to_owned(),
97			"urn:matrix:client:device:*".to_owned(),
98			"urn:matrix:org.matrix.msc2967.client:device:*".to_owned(),
99		]),
100
101		account_management_actions_supported: Some(
102			ACCOUNT_MANAGEMENT_ACTIONS_SUPPORTED
103				.iter()
104				.map(ToString::to_string)
105				.collect(),
106		),
107
108		claims_supported: Some(vec![
109			"iss".to_owned(),
110			"sub".to_owned(),
111			"aud".to_owned(),
112			"exp".to_owned(),
113			"iat".to_owned(),
114			"nonce".to_owned(),
115		]),
116	}))
117}