feat: implement OIDC server for next-gen auth (MSC2965/2964/2966/2967)#342
feat: implement OIDC server for next-gen auth (MSC2965/2964/2966/2967)#342lytedev wants to merge 6 commits intomatrix-construct:mainfrom
Conversation
|
There is https://github.com/element-hq/matrix-authentication-service/tree/main/crates/cli which start MAS |
Looks like that code is under an incompatible software license. I'm a big AGPL fan, but we can't use it here as far as I'm aware =( |
1807530 to
22b5efc
Compare
|
Working great. Added some fixes for Element X (it doesn't request openid scope, which is not mandatory) and implemented real client names (switched from hardcoded "OIDC Client" to the registered name with a fallback). |
|
Thank you both! I'm excited to have a go at this soon. |
|
Tested this with Element X iOS against our production tuwunel instance (Hydra as the upstream IdP) — works great! Two small changes we needed:
Same fix @chbgdn posted above. Element X doesn't request the
Without this, every OIDC session shows up as "OIDC Client" in the device list. With it, you get "Element X" (or whatever the client registered as via DCR). Thanks @lytedev and @chbgdn for the great work on this — was very straightforward to deploy. //cc @lonnithelost |
|
Tested this locally on top of the PR, and these two changes were enough for me as well. I brought up a local isolated OIDC-capable test setup and verified both paths against the real router/handlers:
Path is the same as @siennathesane mentioned |
|
Fixes OIDC loopback redirects for native clients like Fractal. Previously Now loopback HTTP redirect URIs on 127.0.0.1 / ::1 are matched ignoring only the port, while still requiring the rest of the URI to match. Non-loopback redirect URIs still use exact matching. |
- Remove hard openid scope requirement in authorize_route (Element X doesn't send it, and it's optional per OIDC spec) - Use DCR-registered client name as device display name instead of hardcoded "OIDC Client" - Support RFC 8252 loopback redirect URIs for native clients (Fractal) by matching ignoring port for http://127.0.0.1 and http://[::1] Co-Authored-By: chbgdn Co-Authored-By: siennathesane Co-Authored-By: shaba Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
|
Thank you all for these fine additions! For the sake of simplicity and for updating my own deployment. I've gone ahead and included them in a new commit on this PR. |
|
Would it be too much to ask if you could rebase on the latest main branch so we could get CI rolling here? |
|
Not at all. Will do so later today! |
Implements a built-in OIDC authorization server that allows Matrix clients
like Element X to authenticate via OIDC, delegating user authentication
to upstream identity providers (e.g. Kanidm) through the existing SSO flow.
## Endpoints
- GET /_matrix/client/unstable/org.matrix.msc2965/auth_issuer
- GET /.well-known/openid-configuration
- POST /_tuwunel/oidc/registration (Dynamic Client Registration)
- GET /_tuwunel/oidc/authorize → SSO redirect → _complete bridge
- POST /_tuwunel/oidc/token (auth code exchange + refresh)
- POST /_tuwunel/oidc/revoke
- GET /_tuwunel/oidc/jwks
- GET /_tuwunel/oidc/userinfo
- GET /_tuwunel/oidc/account (placeholder)
## Spec compliance fixes
- OAuth error responses use RFC 6749 §5.2 format ({"error": "...", "error_description": "..."})
- PKCE code_verifier validation per RFC 7636 §4.1
- Scope token matching uses exact whitespace-delimited comparison per RFC 6749 §3.3
- Typed ProviderMetadata struct for the discovery document
- DCR includes policy_uri, tos_uri, software_id, software_version per RFC 7591
Refs: matrix-construct#246, matrix-construct#266
… sync - Add policy_uri, tos_uri, software_id, software_version to DCR per RFC 7591 - Add code_verifier length (43-128) and charset validation per RFC 7636 §4.1 - Warn at startup if OIDC server enabled without identity providers - Include Cargo.lock update for ring dependency
- Remove hard openid scope requirement in authorize_route (Element X doesn't send it, and it's optional per OIDC spec) - Use DCR-registered client name as device display name instead of hardcoded "OIDC Client" - Support RFC 8252 loopback redirect URIs for native clients (Fractal) by matching ignoring port for http://127.0.0.1 and http://[::1] Co-Authored-By: chbgdn Co-Authored-By: siennathesane Co-Authored-By: shaba Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
|
Rebased! |
- Remove hard openid scope requirement in authorize_route (Element X doesn't send it, and it's optional per OIDC spec) - Use DCR-registered client name as device display name instead of hardcoded "OIDC Client" - Support RFC 8252 loopback redirect URIs for native clients (Fractal) by matching ignoring port for http://127.0.0.1 and http://[::1] Co-Authored-By: chbgdn Co-Authored-By: siennathesane Co-Authored-By: shaba Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
|
@lytedev Since account/device management panel aren't implemented yet, the stub HTML page is pretty useless. Instead of returning a "not implemented" message, we could just redirect to the IdP's Patch: diff --git a/src/api/client/oidc.rs b/src/api/client/oidc.rs
--- a/src/api/client/oidc.rs
+++ b/src/api/client/oidc.rs
@@ -452,11 +452,30 @@ pub(crate) async fn userinfo_route(
})))
}
-pub(crate) async fn account_route() -> impl IntoResponse {
- axum::response::Html(
- "<html><body><h1>Account Management</h1><p>Account management is not yet implemented. \
- Please use your identity provider to manage your account.</p></body></html>",
- )
+pub(crate) async fn account_route(
+ State(services): State<crate::State>,
+) -> Result<impl IntoResponse> {
+ // Redirect to the identity provider's panel where users can manage
+ // their account, sessions, devices, and profile.
+ let idp = services
+ .config
+ .identity_provider
+ .values()
+ .find(|idp| idp.default)
+ .or_else(|| services.config.identity_provider.values().next())
+ .ok_or_else(|| err!(Config("identity_provider", "No identity provider configured")))?;
+
+ let panel_url = idp
+ .issuer_url
+ .as_ref()
+ .ok_or_else(|| {
+ err!(Config(
+ "issuer_url",
+ "issuer_url is required for account management redirect"
+ ))
+ })?;
+
+ Ok(Redirect::temporary(panel_url.as_str()))
} |
Signed-off-by: Jason Volk <jason@zemos.net>
…r account. Signed-off-by: Jason Volk <jason@zemos.net>
Implements a built-in OIDC authorization server that allows Matrix clients like Element X to authenticate via the next-gen auth flow (MSC2964). User authentication is delegated to upstream identity providers (e.g. Kanidm) through the existing SSO/OAuth client flow.
Endpoints
Features
Spec compliance fixes
{"error": "...", "error_description": "..."}) on token, registration, and revocation endpoints instead of Matrix{"errcode": "M_..."}formatProviderMetadatastruct for the discovery document with documented fields per RFC 8414 / OpenID Connect Discovery 1.0policy_uri,tos_uri,software_id,software_versionper RFC 7591Refs: #246, #266