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 prompt_values: Vec<String> = (services.config.oidc_native_auth
41		&& services.config.allow_registration)
42		.then(|| "create".to_owned())
43		.into_iter()
44		.collect();
45
46	Ok(Json(ProviderMetadata {
47		issuer,
48
49		authorization_endpoint: format!("{base}/_tuwunel/oidc/authorize"),
50
51		registration_endpoint: Some(format!("{base}/_tuwunel/oidc/registration")),
52
53		userinfo_endpoint: Some(format!("{base}/_tuwunel/oidc/userinfo")),
54
55		token_endpoint: format!("{base}/_tuwunel/oidc/token"),
56
57		device_authorization_endpoint: Some(format!("{base}/_tuwunel/oidc/device_authorization")),
58
59		jwks_uri: format!("{base}/_tuwunel/oidc/jwks"),
60
61		account_management_uri: Some(format!("{base}/_tuwunel/oidc/account")),
62
63		revocation_endpoint: Some(format!("{base}/_tuwunel/oidc/revoke")),
64
65		response_modes_supported: Some(vec!["query".to_owned(), "fragment".to_owned()]),
66
67		response_types_supported: vec!["code".to_owned()],
68
69		code_challenge_methods_supported: Some(vec!["S256".to_owned()]),
70
71		id_token_signing_alg_values_supported: Some(vec!["ES256".to_owned()]),
72
73		prompt_values_supported: Some(prompt_values),
74
75		subject_types_supported: Some(vec!["public".to_owned()]),
76
77		claim_types_supported: Some(vec!["normal".to_owned()]),
78
79		grant_types_supported: Some(vec![
80			"authorization_code".to_owned(),
81			"refresh_token".to_owned(),
82			"urn:ietf:params:oauth:grant-type:device_code".to_owned(),
83		]),
84
85		token_endpoint_auth_methods_supported: Some(vec![
86			"none".to_owned(),
87			"client_secret_basic".to_owned(),
88			"client_secret_post".to_owned(),
89		]),
90
91		scopes_supported: Some(vec![
92			"openid".to_owned(),
93			"urn:matrix:client:api:*".to_owned(),
94			"urn:matrix:org.matrix.msc2967.client:api:*".to_owned(),
95			"urn:matrix:client:device:*".to_owned(),
96			"urn:matrix:org.matrix.msc2967.client:device:*".to_owned(),
97		]),
98
99		account_management_actions_supported: Some(
100			ACCOUNT_MANAGEMENT_ACTIONS_SUPPORTED
101				.iter()
102				.map(ToString::to_string)
103				.collect(),
104		),
105
106		claims_supported: Some(vec![
107			"iss".to_owned(),
108			"sub".to_owned(),
109			"aud".to_owned(),
110			"exp".to_owned(),
111			"iat".to_owned(),
112			"nonce".to_owned(),
113		]),
114	}))
115}