WIP: act as a Matrix OIDC auth provider #810

Draft
lafleur wants to merge 59 commits from lafleur/continuwuity:as-oidc-provider into main
First-time contributor

This MR proposes to implement acting as an OIDC authentication provider following the expectations of

  • MSC2965 advertise the auth issuer
  • MSC2964 serve the OIDC token flow
  • MSC2966 dynamic clients registration

The OIDC token flow implies an OAuth transaction implemented with the oxide-auth crate. An enhancement could be to add html templates support for the login and consentment pages (and the future account registration/management pages).

The token flow was tested against areweoidcyet.com, and passes all the steps. Unfortunately, I was unable to use that flow with any app supporting new-style authentication.

MSC4254 (token revocation) should be straightforward to implement, I'll do it soon.

This MR proposes to implement acting as an OIDC authentication provider following the expectations of - [MSC2965](https://github.com/sandhose/matrix-spec-proposals/blob/msc/sandhose/oidc-discovery/proposals/2965-auth-metadata.md) advertise the auth issuer - [MSC2964](https://github.com/sandhose/matrix-spec-proposals/blob/msc/sandhose/oauth2-profile/proposals/2964-oauth2-profile.md) serve the OIDC token flow - [MSC2966](https://github.com/sandhose/matrix-spec-proposals/blob/msc/sandhose/oauth2-dynamic-registration/proposals/2966-oauth2-dynamic-registration.md) dynamic clients registration The OIDC token flow implies an OAuth transaction implemented with the [`oxide-auth`](https://docs.rs/oxide-auth/latest/oxide_auth/) crate. An enhancement could be to add html templates support for the login and consentment pages (and the future account registration/management pages). The token flow was tested against [areweoidcyet.com](https://areweoidcyet.com/client-implementation-guide/), and passes all the steps. Unfortunately, I was unable to use that flow with any app supporting new-style authentication. [MSC4254](https://github.com/matrix-org/matrix-spec-proposals/blob/quenting/oauth2-revocation/proposals/4254-oauth2-revocation.md) (token revocation) should be straightforward to implement, I'll do it soon.
Author
First-time contributor

These MSCs form MSC3861, that recently landed in the spec - see their blog.

These MSCs form [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/blob/hughns/delegated-oidc-architecture/proposals/3861-next-generation-auth.md), that recently landed in the spec - see [their blog](https://matrix.org/blog/2025/04/25/this-week-in-matrix-2025-04-25/).
Owner

Thank you for the PR! I'd like to get #801 merged, then we can work on a basic HTML login page, then we can get login working with Element Web. & Element X as our test targets. We'll also need to add the database tables for dynamic client registration - as it's entirely new tables, that shouldn't cause any database compatibility issues with other conduits, but we'll need to pay attention if any modifications are required elsewhere to the database in the process.
I also want to see if we can move the routing stuff to ruwuma, although that's a lower-priority change.

All that said, this is an excellent start, thank you again! I'm quite happy with using oxide-auth here to avoid maintaining that code ourselves, and it looks well-maintained from a quick glance.

Thank you for the PR! I'd like to get https://forgejo.ellis.link/continuwuation/continuwuity/pulls/801 merged, then we can work on a basic HTML login page, then we can get login working with Element Web. & Element X as our test targets. We'll also need to add the database tables for dynamic client registration - as it's entirely new tables, that shouldn't cause any database compatibility issues with other conduits, but we'll need to pay attention if any modifications are required elsewhere to the database in the process. I also want to see if we can move the routing stuff to ruwuma, although that's a lower-priority change. All that said, this is an excellent start, thank you again! I'm quite happy with using `oxide-auth` here to avoid maintaining that code ourselves, and it looks well-maintained from a quick glance.
nex added this to the 0.5.0-old milestone 2025-04-30 16:28:09 +00:00
Author
First-time contributor

Great ! I noticed you added the askama crate in #801, I should be able to update this MR once you merge it to use its templating system in the current login page - and perhaps the css you added, if it's ment to be site-wide.

Currently I implemented the clients db as a volatile struct using oxide-auth's tooling. This means it's reset at server shutdown. I thought it was fine because I thought clients had to register on each connection anyway, but now I understand that they expect their registration to stay valid across server restart. So yes, I guess we have to add new tables.

BTW, I believe the implementation of msc2965 implies that user registration takes place at a new web endpoint, /_matrix/static/client/register (which is a bit confusing for an user registration endpoint if you ask me). So I'd like to implement that endpoint too, even if I couldn't find the relevant msc.

Great ! I noticed you added the askama crate in #801, I should be able to update this MR once you merge it to use its templating system in the current login page - and perhaps the css you added, if it's ment to be site-wide. Currently I implemented the clients db as a volatile struct using oxide-auth's tooling. This means it's reset at server shutdown. I thought it was fine because I thought clients had to register on each connection anyway, but now I understand that they expect their registration to stay valid across server restart. So yes, I guess we have to add new tables. BTW, I believe the implementation of msc2965 implies that user registration takes place at a new web endpoint, `/_matrix/static/client/register` (which is a bit confusing for an user registration endpoint if you ask me). So I'd like to implement that endpoint too, even if I couldn't find the relevant msc.
Owner

Great ! I noticed you added the askama crate in #801, I should be able to update this MR once you merge it to use its templating system in the current login page - and perhaps the css you added, if it's ment to be site-wide.

That all sounds good to me! The CSS in there at the moment is a pretty rough draft, but ideally, we'd have one piece of base CSS (although perhaps split across multiple actual CSS files) and then per-page tweaks for things that can't be reused.

BTW, I believe the implementation of msc2965 implies that user registration takes place at a new web endpoint, /_matrix/static/client/register (which is a bit confusing for an user registration endpoint if you ask me). So I'd like to implement that endpoint too, even if I couldn't find the relevant msc.

From what I've found, this isn't in the spec and is a synapse-ism, and is what elements will use if a path isn't specified. We can use whatever endoint we want.


/**
 * Path to use when the client does not supported any or all registration flows.
 * Not documented.
 */
internal const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/"
> Great ! I noticed you added the askama crate in #801, I should be able to update this MR once you merge it to use its templating system in the current login page - and perhaps the css you added, if it's ment to be site-wide. That all sounds good to me! The CSS in there at the moment is a pretty rough draft, but ideally, we'd have one piece of base CSS (although perhaps split across multiple actual CSS files) and then per-page tweaks for things that can't be reused. > BTW, I believe the implementation of msc2965 implies that user registration takes place at a new web endpoint, /_matrix/static/client/register (which is a bit confusing for an user registration endpoint if you ask me). So I'd like to implement that endpoint too, even if I couldn't find the relevant msc. From what I've found, this isn't in the spec and is a synapse-ism, and is what elements will use if a path isn't specified. We can use whatever endoint we want. ```kt /** * Path to use when the client does not supported any or all registration flows. * Not documented. */ internal const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/" ```
Author
First-time contributor

I noticed #801 was merged, so I rebased on it and am trying to use askama templates for login and consent webpages. There's a serious issue here : oxide-auth-axum is implemented as a synchronous backend, and porting it to async is non-trivial (see an old MR at their site - that's 1500 lines of code to port oxide-auth-actix to async). But askama is async, and the consent action needs its output in a sync function.

So I'm stuck here right now. I could try and implement that async port in the future, but that will probably take quite some time - and I'm going to have less free time in the weeks to come.

Besides, my main motivation to do this is to support external OIDC providers in the end. But I started thinking that such a feature would have no code in common with this MR.

So the alternative is either more work for the "act as OIDC provider" feature, or start another MR to implement OIDC delegation straight away.

Any opinions on that ?

I noticed #801 was merged, so I rebased on it and am trying to use askama templates for login and consent webpages. There's a serious issue here : oxide-auth-axum is implemented as a synchronous backend, and porting it to async is non-trivial (see [an old MR at their site](https://github.com/HeroicKatora/oxide-auth/pull/165) - that's 1500 lines of code to port oxide-auth-actix to async). But askama _is_ async, and the consent action needs its output in a sync function. So I'm stuck here right now. I could try and implement that async port in the future, but that will probably take quite some time - and I'm going to have less free time in the weeks to come. Besides, my main motivation to do this is to support external OIDC providers in the end. But I started thinking that such a feature would have no code in common with this MR. So the alternative is either more work for the "act as OIDC provider" feature, or start another MR to implement OIDC delegation straight away. Any opinions on that ?
Author
First-time contributor

For the record, someone already implemented async in oxide-auth with axum : https://github.com/mtelahun/axum-oauth

For the record, someone already implemented async in oxide-auth with axum : https://github.com/mtelahun/axum-oauth
Owner

From what I understand, and what I can see in that PR, there is nothing in oxide-auth itself that needs to be changed to be asynchronous as there is no network or disk interaction within the library. That PR adds an example of how you can use asynchronous frameworks with the library.

askama, in contrast, is completely synchronous within its templates. To use asynchronous code you have to run it before rendering the templates and pass it into the template.

Regarding OIDC, this PR from what I understand is a necessary step, and third party OIDC will build upon it. It would be an addition of a new authentication method to the HTML login page. Although this has nothing in common with legacy OIDC (implemented as a different matrix-native authentication flow), that is depreciated and will stop working in some clients soon.

Don't worry about timelines, you're under absolutely no pressure here. I personally am pretty busy with exams right now!

From what I understand, and what I can see in that PR, there is nothing in oxide-auth itself that needs to be changed to be asynchronous as there is no network or disk interaction within the library. That PR adds an example of how you can use asynchronous frameworks with the library. askama, in contrast, is completely synchronous within its templates. To use asynchronous code you have to run it before rendering the templates and pass it into the template. Regarding OIDC, this PR from what I understand is a necessary step, and third party OIDC will build upon it. It would be an addition of a new authentication method to the HTML login page. Although this has nothing in common with legacy OIDC (implemented as a different matrix-native authentication flow), that is depreciated and will stop working in some clients soon. Don't worry about timelines, you're under absolutely no pressure here. I personally am pretty busy with exams right now!
Author
First-time contributor

Aha, I thought askama was asynchronous because I had introduced an async relay function, so I freaked out. Indeed, with your advice I succeeded in returning templates in oxide-auth's authentication flow.

The problem that I have now is that the returned login form is not clickable because of CSP policies. And I couldn't find a way to add headers to OAuthResponses. ATM I'm looking into implementing an OwnerSolicitor that would accept custom headers. It's a bit of a rabbit hole, but hopefully I'll manage something out of it.

Aha, I thought askama was asynchronous because I had introduced an async relay function, so I freaked out. Indeed, with your advice I succeeded in returning templates in oxide-auth's authentication flow. The problem that I have now is that the returned login form is not clickable because of CSP policies. And I couldn't find a way to add headers to `OAuthResponse`s. ATM I'm looking into implementing an `OwnerSolicitor` that would accept custom headers. It's a bit of a rabbit hole, but hopefully I'll manage something out of it.
lafleur force-pushed as-oidc-provider from 7f531034bf
Some checks failed
CI and Artifacts / Test (pull_request) Has been cancelled
CI and Artifacts / Build (pull_request) Has been cancelled
CI and Artifacts / variables (pull_request) Has been cancelled
CI and Artifacts / Docker publish (pull_request) Has been cancelled
Documentation and GitHub Pages / Documentation and GitHub Pages (pull_request) Has been cancelled
to 9a52b6cf9e
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
2025-05-07 12:02:17 +00:00
Compare
Owner

Good work! I'm excited to see where this goes!

I assume you're running into issues with the default CSP. You'll need to set a CSP for the page using something like https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/src/web/mod.rs#L32 rather than just directly returning the string.

Form actions don't support nonces (https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/form-action) so you'll probably want form-action 'self' In addition to the policy on the index page.

Good work! I'm excited to see where this goes! I assume you're running into issues with the default CSP. You'll need to set a CSP for the page using something like https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/src/web/mod.rs#L32 rather than just directly returning the string. Form actions don't support nonces (https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/form-action) so you'll probably want `form-action 'self'` In addition to the policy on the index page.
lafleur force-pushed as-oidc-provider from 9a52b6cf9e
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
to a78887d979
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
2025-05-09 10:13:12 +00:00
Compare
Author
First-time contributor

I had to implement a custom OidcResponse that has CSP header capabilities. In the process I ditched the dependency on oxide-auth-axum. The MR now ships with askama templates support !

The result builds and passes areweoidcyet.com's implementation guide. Docstrings also have been rewritten with a newcomer's standpoint in mind.

I had to implement a custom OidcResponse that has CSP header capabilities. In the process I ditched the dependency on oxide-auth-axum. The MR now ships with askama templates support ! The result builds and passes areweoidcyet.com's [implementation guide](https://areweoidcyet.com/client-implementation-guide/). Docstrings also have been rewritten with a newcomer's standpoint in mind.
lafleur force-pushed as-oidc-provider from a78887d979
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
to eef6e60826
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
2025-05-09 10:43:07 +00:00
Compare
@ -0,0 +13,4 @@
/// A Web response that can be processed by the OIDC authentication flow before
/// being sent over.
#[derive(Default, Clone, Debug)]
pub struct OidcResponse {
Author
First-time contributor

I'm not positive that OidcResponse and OidcRequest should live in src/web - I first thought they belonged in src/api/client/oidc but that results in a cyclic dependency because that API depends on src/web/oidc itself.

Maybe could they be buried deeper into the structure ?

I'm not positive that `OidcResponse` and `OidcRequest` should live in `src/web` - I first thought they belonged in `src/api/client/oidc` but that results in a cyclic dependency because that API depends on `src/web/oidc` itself. Maybe could they be buried deeper into the structure ?
Owner

I think you're right that they belong in API, or at least with the OIDC code. There shouldn't be a cyclic dependency as web doesn't depend on API or router.
If you carry on struggling, you could move the OIDC stuff into its own crate.

I think you're right that they belong in API, or at least with the OIDC code. There shouldn't be a cyclic dependency as web doesn't depend on API or router. If you carry on struggling, you could move the OIDC stuff into its own crate.
Author
First-time contributor

@nex proposed that we try to merge this PR in 0.5.0, so I don't want to move all OIDC stuff in a separate crate ATM, because it would imply more work than I can afford right now. My plan is to keep going with code cleanup. I'll keep that option in mind for later proposals.

@nex proposed that we try to merge this PR in 0.5.0, so I don't want to move all OIDC stuff in a separate crate ATM, because it would imply more work than I can afford right now. My plan is to keep going with code cleanup. I'll keep that option in mind for later proposals.
lafleur marked this conversation as resolved
Jade force-pushed as-oidc-provider from eef6e60826
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
to 0c4917874e
Some checks failed
Release Docker Image / define-variables (pull_request) Successful in 1s
Documentation / Build and Deploy Documentation (pull_request) Failing after 22s
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Failing after 1m2s
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Failing after 45s
Release Docker Image / merge (pull_request) Has been skipped
2025-05-10 11:59:40 +00:00
Compare
Jade approved these changes 2025-05-10 13:58:30 +00:00
Jade left a comment
Owner

I haven't reviewed this for spec yet, just code quality. Ran into a bug I couldn't easily fix before I finished going through 'are we oidc yet'.

Ran clippy, cargo +nightly fmt and typos over it, which created the big diff.

OidcRequest/Response should be located in the same crate as use of oxide-auth. It seems like dependencies have been added in many places to support code being spread out - should be avoided if possible.

Ignoring the templates themselves as I'm assuming they're placeholder for now.

I haven't reviewed this for spec yet, just code quality. Ran into a bug I couldn't easily fix before I finished going through 'are we oidc yet'. Ran clippy, `cargo +nightly fmt` and `typos` over it, which created the big diff. OidcRequest/Response should be located in the same crate as use of oxide-auth. It seems like dependencies have been added in many places to support code being spread out - should be avoided if possible. Ignoring the templates themselves as I'm assuming they're placeholder for now.
@ -58,6 +58,10 @@
#
#port = 8008
# This item is undocumented. Please contribute documentation for it.
Owner

Shouldn't be here. Check to see what well_known does

Shouldn't be here. Check to see what `well_known` does
Author
First-time contributor

fixed in 97b66d2f3e

fixed in 97b66d2f3e
lafleur marked this conversation as resolved
@ -0,0 +77,4 @@
/// Authorize the device based on the user's consent. If the user allows
/// it to access their data, the client may request a token at the
/// [super::token::token] endpoint.
pub(crate) async fn authorize_consent(
Owner

Testing going through https://areweoidcyet.com/ with the server running with the following config:

[global]
server_name = "test.local"
database_path = "./target/database"
auth = { enable_oidc_login = true, enable_oidc_account_management = true }
well_known = { client = "http://127.0.0.1:8008" }

When we get to this point, we get a crash as this seems to return an empty body

Testing going through https://areweoidcyet.com/ with the server running with the following config: ```toml [global] server_name = "test.local" database_path = "./target/database" auth = { enable_oidc_login = true, enable_oidc_account_management = true } well_known = { client = "http://127.0.0.1:8008" } ``` When we get to this point, we get a crash as this seems to return an empty body
Author
First-time contributor

Ahh I get it - if you set

well_known = { client = "http://localhost:8008" }

it succeeds, right ? Then it's solved in 2baeba41

Ahh I get it - if you set ``` toml well_known = { client = "http://localhost:8008" } ``` it succeeds, right ? Then it's solved in 2baeba41
Owner

Nope, not solved. I fixed the issue with IP literals in particular in continuwuation/continuwuity@7ff9d770e3, this is a different issue

[global]
server_name = "test.local"
database_path = "./target/database"
auth = { enable_oidc_login = true, enable_oidc_account_management = true }
well_known = { client = "http://127.0.0.1:8008" }
http://127.0.0.1:8008/_matrix/client/unstable/org.matrix.msc2964/authorize
?response_type = code
&response_mode = fragment
&client_id = tQwCbMNIZU
&redirect_uri = https%3A%2F%2Fareweoidcyet.com%2Fclient-implementation-guide%2Fcallback
&scope = urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*%20urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AEIv9AHM9TmWkhAXS
&state = rdgVyeK58yYEGpFt
&code_challenge_method = S256
&code_challenge = DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0
2025-05-10T19:53:08.906177Z DEBUG router{method=GET path=/_matrix/client/unstable/org.matrix.msc2964/authorize}: tower_http::trace::on_response: finished processing request latency=0 ms status=200
2025-05-10T19:54:14.518548Z  INFO router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/login}:request:handle{active=0 handled=8}: conduwuit_api::client::oidc::login: logging in: "@jade:test.local"
2025-05-10T19:54:14.518974Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/login}: tower_http::trace::on_response: finished processing request latency=37 ms status=200
2025-05-10T19:54:16.098437Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize}:request:handle{active=0 handled=9}: conduwuit_api::client::oidc::authorize: processing user's consent: true - OidcRequest { auth: None, query: Some(NormalizedParameter { inner: {"response_type": Some("code"), "state": Some("rdgVyeK58yYEGpFt"), "response_mode": Some("fragment"), "code_challenge_method": Some("S256"), "allow": Some("true"), "client_id": Some("tQwCbMNIZU"), "code_challenge": Some("DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0"), "scope": Some("urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:EIv9AHM9TmWkhAXS"), "redirect_uri": Some("https://areweoidcyet.com/client-implementation-guide/callback")} }), body: Some(NormalizedParameter { inner: {} }) }

thread 'conduwuit:worker' panicked at src/web/oidc/response.rs:37:30:
body
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
  2025-05-10T19:54:16.099814Z ERROR conduwuit_router::layers: body
    at src/router/layers.rs:190 on conduwuit:worker ThreadId(7)
    in conduwuit_router::layers::panic
    in conduwuit_router::request::handle with active=0 handled=9
    in conduwuit_router::request::request
    in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize

  2025-05-10T19:54:16.100235Z ERROR conduwuit_router::request: 500 Internal Server Error, method: POST, uri: /_matrix/client/unstable/org.matrix.msc2964/authorize?client_id=tQwCbMNIZU&redirect_uri=https%3A%2F%2Fareweoidcyet%2Ecom%2Fclient%2Dimplementation%2Dguide%2Fcallback&scope=urn%3Amatrix%3Aorg%2Ematrix%2Emsc2967%2Eclient%3Aapi%3A%2A%20urn%3Amatrix%3Aorg%2Ematrix%2Emsc2967%2Eclient%3Adevice%3AEIv9AHM9TmWkhAXS&state=rdgVyeK58yYEGpFt&code_challenge=DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0&code_challenge_method=S256&response_type=code&response_mode=fragment&allow=true
    at src/router/request.rs:105 on conduwuit:worker ThreadId(7)
    in conduwuit_router::request::request
    in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize

2025-05-10T19:54:16.100306Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize}: tower_http::trace::on_response: finished processing request latency=2 ms status=500
  2025-05-10T19:54:16.100339Z ERROR tower_http::trace::on_failure: response failed, classification: Status code: 500 Internal Server Error, latency: 2 ms
    at /Users/jade/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tower-http-0.6.2/src/trace/on_failure.rs:93 on conduwuit:worker ThreadId(7)
    in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize

2025-05-10T19:54:16.137886Z ERROR router{method=GET path=/favicon.ico}:request: conduwuit_router::request: 404 Not Found method=GET uri=/favicon.ico
2025-05-10T19:54:16.137974Z DEBUG router{method=GET path=/favicon.ico}: tower_http::trace::on_response: finished processing request latency=0 ms status=404
Nope, not solved. I fixed the issue with IP literals in particular in https://forgejo.ellis.link/continuwuation/continuwuity/commit/7ff9d770e318fdae2ae673a57daf551d005be6e0, this is a different issue ```toml [global] server_name = "test.local" database_path = "./target/database" auth = { enable_oidc_login = true, enable_oidc_account_management = true } well_known = { client = "http://127.0.0.1:8008" } ``` ``` http://127.0.0.1:8008/_matrix/client/unstable/org.matrix.msc2964/authorize ?response_type = code &response_mode = fragment &client_id = tQwCbMNIZU &redirect_uri = https%3A%2F%2Fareweoidcyet.com%2Fclient-implementation-guide%2Fcallback &scope = urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*%20urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AEIv9AHM9TmWkhAXS &state = rdgVyeK58yYEGpFt &code_challenge_method = S256 &code_challenge = DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0 ``` ``` 2025-05-10T19:53:08.906177Z DEBUG router{method=GET path=/_matrix/client/unstable/org.matrix.msc2964/authorize}: tower_http::trace::on_response: finished processing request latency=0 ms status=200 2025-05-10T19:54:14.518548Z INFO router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/login}:request:handle{active=0 handled=8}: conduwuit_api::client::oidc::login: logging in: "@jade:test.local" 2025-05-10T19:54:14.518974Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/login}: tower_http::trace::on_response: finished processing request latency=37 ms status=200 2025-05-10T19:54:16.098437Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize}:request:handle{active=0 handled=9}: conduwuit_api::client::oidc::authorize: processing user's consent: true - OidcRequest { auth: None, query: Some(NormalizedParameter { inner: {"response_type": Some("code"), "state": Some("rdgVyeK58yYEGpFt"), "response_mode": Some("fragment"), "code_challenge_method": Some("S256"), "allow": Some("true"), "client_id": Some("tQwCbMNIZU"), "code_challenge": Some("DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0"), "scope": Some("urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:EIv9AHM9TmWkhAXS"), "redirect_uri": Some("https://areweoidcyet.com/client-implementation-guide/callback")} }), body: Some(NormalizedParameter { inner: {} }) } thread 'conduwuit:worker' panicked at src/web/oidc/response.rs:37:30: body note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 2025-05-10T19:54:16.099814Z ERROR conduwuit_router::layers: body at src/router/layers.rs:190 on conduwuit:worker ThreadId(7) in conduwuit_router::layers::panic in conduwuit_router::request::handle with active=0 handled=9 in conduwuit_router::request::request in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize 2025-05-10T19:54:16.100235Z ERROR conduwuit_router::request: 500 Internal Server Error, method: POST, uri: /_matrix/client/unstable/org.matrix.msc2964/authorize?client_id=tQwCbMNIZU&redirect_uri=https%3A%2F%2Fareweoidcyet%2Ecom%2Fclient%2Dimplementation%2Dguide%2Fcallback&scope=urn%3Amatrix%3Aorg%2Ematrix%2Emsc2967%2Eclient%3Aapi%3A%2A%20urn%3Amatrix%3Aorg%2Ematrix%2Emsc2967%2Eclient%3Adevice%3AEIv9AHM9TmWkhAXS&state=rdgVyeK58yYEGpFt&code_challenge=DV2ZxyJZ0MWLPBUMmKjsN35LdjFoVmEe8YSbsRKTLx0&code_challenge_method=S256&response_type=code&response_mode=fragment&allow=true at src/router/request.rs:105 on conduwuit:worker ThreadId(7) in conduwuit_router::request::request in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize 2025-05-10T19:54:16.100306Z DEBUG router{method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize}: tower_http::trace::on_response: finished processing request latency=2 ms status=500 2025-05-10T19:54:16.100339Z ERROR tower_http::trace::on_failure: response failed, classification: Status code: 500 Internal Server Error, latency: 2 ms at /Users/jade/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tower-http-0.6.2/src/trace/on_failure.rs:93 on conduwuit:worker ThreadId(7) in conduwuit_router::layers::router with method=POST path=/_matrix/client/unstable/org.matrix.msc2964/authorize 2025-05-10T19:54:16.137886Z ERROR router{method=GET path=/favicon.ico}:request: conduwuit_router::request: 404 Not Found method=GET uri=/favicon.ico 2025-05-10T19:54:16.137974Z DEBUG router{method=GET path=/favicon.ico}: tower_http::trace::on_response: finished processing request latency=0 ms status=404 ```
Author
First-time contributor

OK, obviously I was too quick using OidcResponse in api/client/oidc/discovery.rs. This specific issue should be fixed with
-e09d60a6df- - discarded by 357c2335 .

I'm a bit jealous of your runtime logs, I only have access to a release binary, because I don't have enough disk space to compile debug builds. If I had access to that when debugging oxide-auth at the beggining, I'd have saved quite some hours !

OK, obviously I was too quick using `OidcResponse` in `api/client/oidc/discovery.rs`. This specific issue should be fixed with -e09d60a6df- - discarded by 357c2335 . I'm a bit jealous of your runtime logs, I only have access to a release binary, because I don't have enough disk space to compile debug builds. If I had access to that when debugging oxide-auth at the beggining, I'd have saved quite some hours !
Author
First-time contributor

Actually, OidcResponse needs a deeper rewrite. I thought I had copied over all functionalities from oxide-auth-axum's OAuthResponse, but it appears I copied the wrong implementation. I'm on it now. BTW my machine built a debug build this night, thanks to nix --store ... and the workaround I published in #822

Actually, `OidcResponse` needs a deeper rewrite. I thought I had copied over all functionalities from oxide-auth-axum's `OAuthResponse`, but it appears I copied the wrong implementation. I'm on it now. BTW my machine built a debug build this night, thanks to `nix --store ...` and the workaround I published in #822
Author
First-time contributor

Done in 357c2335 - rewrite of OidcResponse's IntoResponse implementation. Should fix the issue at hand (the location header was not set), and a bunch of others.

Done in 357c2335 - rewrite of `OidcResponse`'s `IntoResponse` implementation. Should fix the issue at hand (the location header was not set), and a bunch of others.
Author
First-time contributor

Can you confirm this build passes areweoidcyet.com's test page ?

Can you confirm this build passes areweoidcyet.com's test page ?
Owner

It does now.

It does now.
nex marked this conversation as resolved
@ -0,0 +34,4 @@
http::StatusCode::NOT_FOUND,
ClientErrorBody::Standard {
kind: ClientErrorKind::Unrecognized,
message: "This homeserver doesn't do OIDC authentication.".to_owned(),
Owner

'This homeserver has disabled OIDC authentication'

'This homeserver has disabled OIDC authentication'
Author
First-time contributor

fixed in f4e0ff9e13

fixed in f4e0ff9e13
lafleur marked this conversation as resolved
@ -0,0 +71,4 @@
.unwrap(),
),
revocation_endpoint: issuer
.join("_matrix/client/unstable/org.matrix.msc2964/revoke")
Owner

Missing starting slash here?

Missing starting slash here?
Author
First-time contributor

Nice catch ! fixed in 0781453572

Nice catch ! fixed in 0781453572
lafleur marked this conversation as resolved
@ -117,6 +117,21 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
.ruma_route(&client::get_protocols_route)
.route("/_matrix/client/unstable/thirdparty/protocols",
get(client::get_protocols_route_unstable))
// MSC2965 route.
Owner

Nitpicking but include the MSC titles please

Nitpicking but include the MSC titles please
Author
First-time contributor

Right ! fixed in f4e0ff9e13

Right ! fixed in f4e0ff9e13
lafleur marked this conversation as resolved
@ -274,0 +275,4 @@
if auth.enable_oidc_login && config.well_known.client.is_none() {
return Err!(Config(
"auth.enable_oidc_login",
"Oidc authentication is enabled but the well-known client is not set."
Owner

OIDC / HTML URL shouldn't be tied to the client-server API URL. Can use it as a default, but should be a separate config option

OIDC / HTML URL shouldn't be tied to the client-server API URL. Can use it as a default, but should be a separate config option
Author
First-time contributor

I believed that until we implement delegation, the OIDC issuer should run at the same URL as the server. Should that be config.well_known.server ?

And, if we make this a configurable default, then if the admin sets it to some other server, that server will expect all sorts of things like client provisioning. I naïvely thought we could avoid that, and implement delegation over standard OIDC servers in a later MR.

Maybe it's silly - or too ambitious. I don't get why Matrix did that overlay over OIDC. I hope Conduwuit can support standard OIDC issuers like Kanidm. Does that sound realistic ?

I believed that until we implement delegation, the OIDC issuer should run at the same URL as the server. Should that be `config.well_known.server` ? And, if we make this a configurable default, then if the admin sets it to some other server, that server will expect all sorts of things like client provisioning. I naïvely thought we could avoid that, and implement delegation over standard OIDC servers in a later MR. Maybe it's silly - or too ambitious. I don't get why Matrix did that overlay over OIDC. I hope Conduwuit can support standard OIDC issuers like Kanidm. Does that sound realistic ?
Owner

So this is not requesting delegation, but for the case where, for example, continuwuity is running on matrix.somedomain.com, but the user wants login pages, etc to appear on somedomain.com (and they've set their reverse proxy up correctly for that). For that to work, they'd need to be able to set the URL to a different value to the C/S URL

So this is not requesting delegation, but for the case where, for example, continuwuity is running on matrix.somedomain.com, but the user wants login pages, etc to appear on somedomain.com (and they've set their reverse proxy up correctly for that). For that to work, they'd need to be able to set the URL to a different value to the C/S URL
Owner

In fact, this but might not even be necessary, looks like it defaults to "Continuwuity" in the only place it's used
image

In fact, this but might not even be necessary, looks like it defaults to "Continuwuity" in the only place it's used ![image](/attachments/97d30e0d-40bf-49d5-9ed1-75b724d76961)
Author
First-time contributor

The well-known client is used in src/api/client/oidc/discovery.rs to advertise the OIDC issuer. That's why I check on it at startup - if we are the OIDC issuer, we need an URL to advertise.

That should be the well-known server instead, right ?

On the other hand, I wanted the login and consent page to display the current server name as a title. That's what the hostname variable is for (that's in src/api/client/oidc/login.rs). The well-known client was a hasty fill for the job. Is there a config variable that would be more adapted ? Or should we add eg an advertised_servername in [global.auth] ?

The well-known client is used in `src/api/client/oidc/discovery.rs` to advertise the OIDC issuer. That's why I check on it at startup - if we are the OIDC issuer, we need an URL to advertise. That should be the well-known server instead, right ? On the other hand, I wanted the login and consent page to display the current server name as a title. That's what the `hostname` variable is for (that's in `src/api/client/oidc/login.rs`). The well-known client was a hasty fill for the job. Is there a config variable that would be more adapted ? Or should we add eg an `advertised_servername` in `[global.auth]` ?
Owner

For displaying the server name, you want config.server_name, which is what ends up being a part of the username.

For the OIDC Discovery document, client is OK as a default, given that it's usually clients accessing those endpoints. I'll have a more in-depth look at that when I review for spec/functionality.

For displaying the server name, you want `config.server_name`, which is what ends up being a part of the username. For the OIDC Discovery document, client is OK as a default, given that it's usually clients accessing those endpoints. I'll have a more in-depth look at that when I review for spec/functionality.
Author
First-time contributor

OK ! Added in 2baeba41 - proxy users would set that variable anyway, right ? So this settles that, doesn't it ?

OK ! Added in 2baeba41 - proxy users would set that variable anyway, right ? So this settles that, doesn't it ?
Owner

Yep, you have to set server_name to start up the server

Yep, you *have* to set `server_name` to start up the server
Jade marked this conversation as resolved
@ -1882,0 +1892,4 @@
/// The URL where the user is able to access the account management
/// capabilities of the homeserver. Only used if `enable_oidc_login` is set.
/// Unset by default.
pub enable_oidc_account_management: bool,
Owner

Doc comment doesn't match here. Should have a default set.

Doc comment doesn't match here. Should have a default set.
Author
First-time contributor

I updated it to match the implementation in 97b66d2f3e - I guess the question to use a set or just a boolean is dependent on our other conversation on src/core/config/check.rs.

I updated it to match the implementation in 97b66d2f3e - I guess the question to use a set or just a boolean is dependent on our other conversation on `src/core/config/check.rs`.
Jade marked this conversation as resolved
@ -111,6 +111,7 @@ webpage.workspace = true
webpage.optional = true
blurhash.workspace = true
blurhash.optional = true
oxide-auth.workspace = true
Owner

Is there a way we can avoid adding the oxide-auth dependency to so many crates? Reexporting necessary types, maybe

Is there a way we can avoid adding the oxide-auth dependency to so many crates? Reexporting necessary types, maybe
Author
First-time contributor

That would need a separate crate as you proposed.

That would need a separate crate as you proposed.
Author
First-time contributor

@Jade do you think this dependency is acceptable as is for now ? It's true that it means more compile time for everybody, including people that don't use or want OIDC. Perhaps an alternative would be an OIDC feature flag ? I noticed that an LDAP feature flag landed in continuwuity meanwhile.

In my opinion, OIDC is the most mainstream future for Matrix authentication flow. It's both what Matrix specs advertise, and what brings more security features (clients never get a hand on user authentication material). So to me it makes sense to integrate it in the permanent codebase. I'm indeed very open to other clues though.

@Jade do you think this dependency is acceptable as is for now ? It's true that it means more compile time for everybody, including people that don't use or want OIDC. Perhaps an alternative would be an OIDC feature flag ? I noticed that an LDAP feature flag landed in continuwuity meanwhile. In my opinion, OIDC is the most mainstream future for Matrix authentication flow. It's both what Matrix specs advertise, and what brings more security features (clients never get a hand on user authentication material). So to me it makes sense to integrate it in the permanent codebase. I'm indeed very open to other clues though.
Owner

It's something that can be cleaned up later, don't worry about it.

It's something that can be cleaned up later, don't worry about it.
Author
First-time contributor

BTW I'm sorry, I can't run cargo +nightly fmt on my machine right now, lack of resources here. I'll try to set it up.

BTW I'm sorry, I can't run `cargo +nightly fmt` on my machine right now, lack of resources here. I'll try to set it up.
Owner

DW, I'm about to do that + fix some compile errors

DW, I'm about to do that + fix some compile errors
@ -0,0 +48,4 @@
pub fn preconfigured() -> Self {
Self {
registrar: Mutex::new(
vec![Client::public(
Author
First-time contributor

Before I forget about this old commit: this is purely illustrative, stating how to populate the initial client registry with an app. We should remove that sample client before long.

Before I forget about this old commit: this is purely illustrative, stating how to populate the initial client registry with an app. We should remove that sample client before long.
Author
First-time contributor

Done in the registrar rewrite a9246002

Done in the registrar rewrite a9246002
lafleur marked this conversation as resolved
lafleur force-pushed as-oidc-provider from e09d60a6df
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
to 357c233576
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Release Docker Image / define-variables (pull_request) Has been cancelled
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been cancelled
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been cancelled
Release Docker Image / merge (pull_request) Has been cancelled
2025-05-11 13:18:11 +00:00
Compare
@ -118,2 +118,4 @@
.route("/_matrix/client/unstable/thirdparty/protocols",
get(client::get_protocols_route_unstable))
// MSC2965: OAuth 2.0 Authorization Server Metadata discovery.
.route("/_matrix/client/unstable/org.matrix.msc2965/auth_metadata",
Author
First-time contributor

Any idea why Element X doesn't use the OIDC login endpoint ? I thought that maybe they don't use the unstable endpoints URLs anymore - the related MSCs were merged recently. Should I try to remove the unstable prefixes from the routes ?

Any idea why Element X doesn't use the OIDC login endpoint ? I thought that maybe they don't use the unstable endpoints URLs anymore - the related MSCs were merged recently. Should I try to remove the unstable prefixes from the routes ?
Owner

You can try that, don't forget you can register the same handler on multiple routes.

You can try that, don't forget you can register the same handler on multiple routes.
Author
First-time contributor

I did try that (remove the unstable prefix from the OIDC discovery endpoint), the issue is still the same.

I must say I don't know what to do else. I did have some oauth knowledge before starting this MR because I already had implemented a client in react, but I'm definitely no expert in Matrix clients - I just used to run a conduwuit server for my family. This MR already contains all I can contribute at the moment, I'm afraid. Besides, I have plenty of paid work in another field coming up for the next two months, so I can't invest much time in debugging this issue.

If someone comes up with something else to try, I might find a bit of time for that though.

I did try that (remove the unstable prefix from the OIDC discovery endpoint), the issue is still the same. I must say I don't know what to do else. I did have some oauth knowledge before starting this MR because I already had implemented a client in react, but I'm definitely no expert in Matrix clients - I just used to run a conduwuit server for my family. This MR already contains all I can contribute at the moment, I'm afraid. Besides, I have plenty of paid work in another field coming up for the next two months, so I can't invest much time in debugging this issue. If someone comes up with something else to try, I might find a bit of time for that though.
Owner

I'll have a look and see what I can figure out, but if I can't get it to work, I guess we can continue without that for now.

I'll have a look and see what I can figure out, but if I can't get it to work, I guess we can continue without that for now.
Owner

Taking a look at my Element X IOS Nightly logs, I see this:

2025-05-31T18:44:13.477754Z DEBUG matrix_sdk::http_client::native: Sending request num_attempt=1 | crates/matrix-sdk/src/http_client/native.rs:78 | spans: send{request_id="REQ-3" method=GET uri="https://matrix-client.matrix.org/_matrix/client/unstable/org.matrix.msc2965/auth_metadata"}

I'll see if I can figure out why it's not making the request here

Taking a look at my Element X IOS Nightly logs, I see this: `2025-05-31T18:44:13.477754Z DEBUG matrix_sdk::http_client::native: Sending request num_attempt=1 | crates/matrix-sdk/src/http_client/native.rs:78 | spans: send{request_id="REQ-3" method=GET uri="https://matrix-client.matrix.org/_matrix/client/unstable/org.matrix.msc2965/auth_metadata"}` I'll see if I can figure out why it's not making the request here
Owner

This seems to work now

This seems to work now
nex marked this conversation as resolved
Jade force-pushed as-oidc-provider from 9c7c7e7798
Some checks failed
Release Docker Image / define-variables (pull_request) Failing after 0s
Release Docker Image / build-image (linux/amd64, linux-amd64) (pull_request) Has been skipped
Release Docker Image / build-image (linux/arm64, linux-arm64) (pull_request) Has been skipped
Release Docker Image / merge (pull_request) Has been skipped
Documentation / Build and Deploy Documentation (pull_request) Failing after 41s
to bb9e8af4e0
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 23s
2025-05-21 11:48:14 +00:00
Compare
nex requested changes 2025-05-31 23:02:09 +00:00
@ -0,0 +9,4 @@
pub redirect_uri: Url,
pub scope: String,
pub state: String,
pub code_challenge: String,
Owner

Now that clients are confirmed to be connecting correctly (confirmed in #development:continuwuity.org, I got mxtoken and Element X iOS to correctly detect and start using OIDC), there's an issue with the initial redirect to /authorize:

Failed to deserialize query string: missing field code_challenge

In the initial request, this, and other fields are not provided, but required by this struct (and similar ones like LoginQuery).

The only five query params provided at the start of the flow are client_id, response_type, redirect_uri, state, and scope. The rest are seemingly used later on?

Now that clients are confirmed to be connecting correctly (confirmed in `#development:continuwuity.org`, I got [mxtoken](https://timedout.uk/mxtoken.html) and Element X iOS to correctly detect and start using OIDC), there's an issue with the initial redirect to `/authorize`: `Failed to deserialize query string: missing field code_challenge` In the initial request, this, and other fields are not provided, but required by this struct (and similar ones like LoginQuery). The only five query params provided at the start of the flow are `client_id`, `response_type`, `redirect_uri`, `state`, and `scope`. The rest are seemingly used later on?
First-time contributor

Both code_challenge and code_challenge_method are necessary for PKCE, which is required as per the MSC on OIDC login. If a client is truly MSC2964 compatible, those parameters must be sent.

The same MSC also appears to suggest the response_mode parameter is required (it is explicitly mentioned multiple times without a default, and has the client check the server for compatibility with different modes), so it should also be sent every time. Which client wasn't sending these?

Both `code_challenge` and `code_challenge_method` are necessary for PKCE, which is required as per the MSC on OIDC login. If a client is truly MSC2964 compatible, those parameters must be sent. The same MSC also appears to suggest the `response_mode` parameter is required (it is explicitly mentioned multiple times without a default, and has the client check the server for compatibility with different modes), so it should also be sent every time. Which client wasn't sending these?
Owner

Yeah, I seem to get different missing params depending on which OIDC-capable client I initiate from. I'll have to wait until we can figure out why Element Web doesn't work with this impl since debugging with Element X is suboptimal

Yeah, I seem to get different missing params depending on which OIDC-capable client I initiate from. I'll have to wait until we can figure out why Element Web doesn't work with this impl since debugging with Element X is suboptimal
Author
First-time contributor

@ty wrote in #810 (comment):

Both code_challenge and code_challenge_method are necessary for PKCE, which is required as per the MSC on OIDC login. If a client is truly MSC2964 compatible, those parameters must be sent.

The same MSC also appears to suggest the response_mode parameter is required (it is explicitly mentioned multiple times without a default, and has the client check the server for compatibility with different modes), so it should also be sent every time. Which client wasn't sending these?

Specifically, Fractal isn't.

@ty wrote in https://forgejo.ellis.link/continuwuation/continuwuity/pulls/810#issuecomment-16097: > Both `code_challenge` and `code_challenge_method` are necessary for PKCE, which is required as per the MSC on OIDC login. If a client is truly MSC2964 compatible, those parameters must be sent. > > The same MSC also appears to suggest the `response_mode` parameter is required (it is explicitly mentioned multiple times without a default, and has the client check the server for compatibility with different modes), so it should also be sent every time. Which client wasn't sending these? Specifically, Fractal isn't.
Owner

This suggests that the rust SDK isn't, probably worth a bug report to them at some point.

This suggests that the rust SDK isn't, probably worth a bug report to them at some point.
Author
First-time contributor

Hey, I just tried the OIDC login flow with both fractal and matrix-rust-sdk's example-oauth-cli, and I can see the authorize request bears code_challenge and code_challenge_method in both cases (this is shown when using conduwuit_api::client::oidc::authorize=trace in logs). I guess this was solved upstream since then.

This discussion may be closed as far as I'm concerned. I leave it open so that @Jade can check they're OK with this.

Hey, I just tried the OIDC login flow with both fractal and matrix-rust-sdk's `example-oauth-cli`, and I can see the `authorize` request bears `code_challenge` and `code_challenge_method` in both cases (this is shown when using `conduwuit_api::client::oidc::authorize=trace` in logs). I guess this was solved upstream since then. This discussion may be closed as far as I'm concerned. I leave it open so that @Jade can check they're OK with this.
Owner

I'm going to spend some time on this over the next week to see if we can get it working. It doesn't seem far off being finished.

I'm going to spend some time on this over the next week to see if we can get it working. It doesn't seem far off being finished.
Author
First-time contributor

Great ! I'm totally busy until the 8th of june, so I won't be able to help this week, but I'll try to follow your advances remotely - indeed, I think the MR is pretty close to the needed functionality, and I'm confident you'll find out how to make it work.

I guess the code will need some cleanup once it works, I think I'll focus on that when I'm back.

Thanks @nex

Great ! I'm totally busy until the 8th of june, so I won't be able to help this week, but I'll try to follow your advances remotely - indeed, I think the MR is pretty close to the needed functionality, and I'm confident you'll find out how to make it work. I guess the code will need some cleanup once it works, I think I'll focus on that when I'm back. Thanks @nex
Owner

Got blindsided by some things that took far greater priority, apologies. Will definitely come to this when I get time.

Got blindsided by some things that took far greater priority, apologies. Will definitely come to this when I get time.
nex force-pushed as-oidc-provider from 9dbd0e654c
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 34s
to aa206e4f90
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Failing after 0s
Checks / Prefligit / prefligit (pull_request) Failing after 23s
2025-07-02 01:02:42 +00:00
Compare
Owner

Just re-ran this though https://areweoidcyet.com/client-implementation-guide/ and it works fine, so I'm going to start reaching out to relevant people to see if we can figure out why clients aren't using this correctly.

Just re-ran this though https://areweoidcyet.com/client-implementation-guide/ and it works fine, so I'm going to start reaching out to relevant people to see if we can figure out why clients aren't using this correctly.
@ -107,0 +107,4 @@
// external structure; separate section
pub auth: Option<AuthConfig>,
/// The UNIX socket conduwuit will listen on.
Owner

You might wanna read through the diff for things like this by the way

You might wanna read through the diff for things like this by the way
Author
First-time contributor

Sorry, which diff ? What did I miss ?

Recently I thought that auth should not be optional BTW, and it makes it tedious to find out what the auth system is in code.

Sorry, which diff ? What did I miss ? Recently I thought that `auth` should not be optional BTW, and it makes it tedious to find out what the auth system is in code.
Owner

The PR diff; you accidentally replaced a Continuwuity with a conduwuit

The PR diff; you accidentally replaced a Continuwuity with a conduwuit
Owner

Yeah it can work to have it not optional if you implement default so existing config isn't affected

Yeah it can work to have it not optional if you implement default so existing config isn't affected
Author
First-time contributor

@Jade wrote in #810 (comment):

The PR diff; you accidentally replaced a Continuwuity with a conduwuit

Fixed in 287e44b1

@Jade wrote in https://forgejo.ellis.link/continuwuation/continuwuity/pulls/810#issuecomment-17221: > The PR diff; you accidentally replaced a Continuwuity with a conduwuit Fixed in 287e44b1
lafleur marked this conversation as resolved
@ -0,0 +32,4 @@
fn try_from(value: OidcRequest) -> Result<Self, LoginError> {
let body = value.body().expect("body in OidcRequest");
let Some(username) = body.unique_value("username") else {
Owner

I feel like this should be codegen-able (eg serde)

I feel like this should be codegen-able (eg serde)
Author
First-time contributor

With these commits, the oidc authentication flow now succeeds with the Fractal client.

Details on the updates :

  • #98c7795982 and #696adfc90b let conduwuit tolerate an oidc auth request without a response_mode field. In Matrix this field can only contain the literal "fragment", which makes it superfluous for the clients. Fractal omits it, this fixes that.
  • #511e60b41d adds support for private clients. It lacks a proper secret generator.
  • #6d9aee4d9f adds ClientMap, an implementation of a client registrar, which helps debugging with some tracing, and should help integrate its data in the database. I know strictly nothing about rocksdb and little more about databases in general, so I keep clear ATM.
  • #2784eec60a fixes the fact that oxide-auth can't ignore the port on localhost (as it should) when localhost is spelled with a literal IP. It's worked around by substituting them for the test and sending back the proper url. This was easy to implement within ClientMap.
  • #a536bc4c97 tries to fix a chrome/chromium issue with CSP form-data instructions.
  • #c059dbb337 updates the consent flow to convey the user_id in the consent value up to the token flow

There are more issues to be solved, but now rather on the database side, would you dear reviewers give this MR a try ? I can witness it builds all right.

With these commits, the oidc authentication flow now succeeds with the Fractal client. Details on the updates : - #98c7795982 and #696adfc90b let conduwuit tolerate an oidc auth request without a `response_mode` field. In Matrix this field can only contain the literal "fragment", which makes it superfluous for the clients. Fractal omits it, this fixes that. - #511e60b41d adds support for private clients. It lacks a proper secret generator. - #6d9aee4d9f adds `ClientMap`, an implementation of a client registrar, which helps debugging with some tracing, and should help integrate its data in the database. I know strictly nothing about rocksdb and little more about databases in general, so I keep clear ATM. - #2784eec60a fixes the fact that oxide-auth can't ignore the port on localhost (as it should) when localhost is spelled with a literal IP. It's worked around by substituting them for the test and sending back the proper url. This was easy to implement within `ClientMap`. - #a536bc4c97 tries to fix a chrome/chromium issue with CSP `form-data` instructions. - #c059dbb337 updates the consent flow to convey the user_id in the consent value up to the token flow There are more issues to be solved, but now rather on the database side, would you dear reviewers give this MR a try ? I can witness it builds all right.
nex modified the milestone from 0.5.0-old to 0.5.0 2025-10-15 03:05:48 +00:00
Owner

milestoning for 0.5.0 but really not sure if it'll make the cut this time around, more likely to be 0.6.0. Was gonna be in one of the earlier RCs but other priorities arose

milestoning for 0.5.0 but really not sure if it'll make the cut this time around, more likely to be 0.6.0. Was gonna be in one of the earlier RCs but [other priorities arose](https://spec.matrix.org/v1.16/changelog/v1.16/)
Author
First-time contributor

OK - I have a working impl at home, I'll push it ASAP so you folks can assess that with latest developments.

OK - I have a working impl at home, I'll push it ASAP so you folks can assess that with latest developments.
lafleur force-pushed as-oidc-provider from 81713273da
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Checks / Prefligit / prefligit (pull_request) Has been cancelled
to 416ffd4820
Some checks failed
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Release Docker Image / Build linux-amd64 (release) (pull_request) Blocked by required conditions
Release Docker Image / Build linux-arm64 (release) (pull_request) Blocked by required conditions
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Blocked by required conditions
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Blocked by required conditions
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Blocked by required conditions
Release Docker Image / Create Max-Perf Manifest (pull_request) Blocked by required conditions
Documentation / Build and Deploy Documentation (pull_request) Has been cancelled
Update flake hashes / update-flake-hashes (pull_request) Has been cancelled
2025-11-03 22:28:47 +00:00
Compare
Author
First-time contributor

Hey folks, long time no hear ! I just pushed some improvements over this PR :

  • client registration flow + corrections (first and penultimate commits) : I struggled a bit to get it right between client and device registration, but now I think it's fine. I added some docstrings where things get hairy
  • the client registrar is now using the database as a backend. I implemented Registrar directly over the OIDC Service, it works like a charm ! I added two segments in the db, one with the serialized oidc clients, one mapping device ids with client ids. I made wild guesses on the db descriptors though, I'm really incompetent in that field (and quite happy like that :)
  • private clients now get ruma's secret generator
  • I kept a commit that just unlocks log levels on release builds. That will need to go away I guess, I just can't do without it because I regularly need those logs and can't afford a debug build on my machines (hard-drive wise)

I rebased on current main and checked everything works as it should. And it does !

Hey folks, long time no hear ! I just pushed some improvements over this PR : - client registration flow + corrections (first and penultimate commits) : I struggled a bit to get it right between client and device registration, but now I think it's fine. I added some docstrings where things get hairy - the client registrar is now using the database as a backend. I implemented `Registrar` directly over the OIDC `Service`, it works like a charm ! I added two segments in the db, one with the serialized oidc clients, one mapping device ids with client ids. I made wild guesses on the db descriptors though, I'm really incompetent in that field (and quite happy like that :) - private clients now get ruma's secret generator - I kept a commit that just unlocks log levels on release builds. That will need to go away I guess, I just can't do without it because I regularly need those logs and can't afford a debug build on my machines (hard-drive wise) I rebased on current main and checked everything works as it should. And it does !
Author
First-time contributor

BTW, I tested the OIDC feature against matrix-rust-sdk's example-oauth-cli, and it works. That's good news, because it's precisely the sdk used by fractal and element X. I succeeded in logging in using OIDC in fractal too using firefox. I had issues with chromium's CSP, but I can't remember the details. Element X still fails to propose the OIDC login flow, and I can't figure any clue on why.

Disclaimer : I won't go further into debugging clients' login flow failures, mostly because it's extremely tedious with release builds (which I'm stuck with, as mentioned above). Changing a comma leads to almost half an hour of build time, which regularly fail short of disk space. In which case I'm forced to delete all build artifacts, and wait around an hour for a fresh build.

This being said, I'd like to work on some improvements to this PR, such as letting refresh tokens survive continuwuity's restart. Once that's done, the next thing that comes to mind (besides cleanup) is having account management pages in continuwuity.

Talking about cleanup, I'm sorry I can't format my commits (because it requires nightly rustc, which I can't afford either). Would there be a workaround ? Otherwise we'll have to rely on some generous soul that would reformat them and push them back (as one of my knowledge did in the past).

BTW, I tested the OIDC feature against matrix-rust-sdk's `example-oauth-cli`, and it works. That's good news, because it's precisely the sdk used by fractal and element X. I succeeded in logging in using OIDC in fractal too using firefox. I had issues with chromium's CSP, but I can't remember the details. Element X still fails to propose the OIDC login flow, and I can't figure any clue on why. Disclaimer : I won't go further into debugging clients' login flow failures, mostly because it's extremely tedious with release builds (which I'm stuck with, as mentioned above). Changing a comma leads to almost half an hour of build time, which regularly fail short of disk space. In which case I'm forced to delete all build artifacts, and wait around an hour for a fresh build. This being said, I'd like to work on some improvements to this PR, such as letting refresh tokens survive continuwuity's restart. Once that's done, the next thing that comes to mind (besides cleanup) is having account management pages in continuwuity. Talking about cleanup, I'm sorry I can't format my commits (because it requires nightly rustc, which I can't afford either). Would there be a workaround ? Otherwise we'll have to rely on some generous soul that would reformat them and push them back (as one of my knowledge did in the past).
Owner

Talking about cleanup, I'm sorry I can't format my commits (because it requires nightly rustc, which I can't afford either). Would there be a workaround ? Otherwise we'll have to rely on some generous soul that would reformat them and push them back (as one of my knowledge did in the past).

Don't worry too much about the formatting, we can always run a reformat and push back to your branch if necessary. All that matters is that gets done at some point before merge, until then it's not a big deal :)

Disclaimer : I won't go further into debugging clients' login flow failures, mostly because it's extremely tedious with release builds (which I'm stuck with, as mentioned above). Changing a comma leads to almost half an hour of build time, which regularly fail short of disk space. In which case I'm forced to delete all build artifacts, and wait around an hour for a fresh build.

That's fine - if this is implemented according to what is defined in the spec, and it's still not working on some clients, then I'm inclined to believe it's a bug in those clients and we can report that to them if needs be. We can also rebase out some commits like the one you added for debug logs before merging, don't worry too much about keeping a clean git log.

This being said, I'd like to work on some improvements to this PR, such as letting refresh tokens survive continuwuity's restart. Once that's done, the next thing that comes to mind (besides cleanup) is having account management pages in continuwuity.

Do you want to do those in a separate PR, so we can get an initial implementation landed into the next release? You don't have to, but it might be worth considering given that we're aiming to get 0.5.0 out in the nearish future.

> Talking about cleanup, I'm sorry I can't format my commits (because it requires nightly rustc, which I can't afford either). Would there be a workaround ? Otherwise we'll have to rely on some generous soul that would reformat them and push them back (as one of my knowledge did in the past). Don't worry too much about the formatting, we can always run a reformat and push back to your branch if necessary. All that matters is that gets done at some point before merge, until then it's not a big deal :) > Disclaimer : I won't go further into debugging clients' login flow failures, mostly because it's extremely tedious with release builds (which I'm stuck with, as mentioned above). Changing a comma leads to almost half an hour of build time, which regularly fail short of disk space. In which case I'm forced to delete all build artifacts, and wait around an hour for a fresh build. That's fine - if this is implemented according to what is defined in the spec, and it's still not working on some clients, then I'm inclined to believe it's a bug in those clients and we can report that to them if needs be. We can also rebase out some commits like the one you added for debug logs before merging, don't worry too much about keeping a clean git log. > This being said, I'd like to work on some improvements to this PR, such as letting refresh tokens survive continuwuity's restart. Once that's done, the next thing that comes to mind (besides cleanup) is having account management pages in continuwuity. Do you want to do those in a separate PR, so we can get an initial implementation landed into the next release? You don't have to, but it might be worth considering given that we're aiming to get 0.5.0 out in the nearish future.
Author
First-time contributor

Do you want to do those in a separate PR, so we can get an initial implementation landed into the next release? You don't have to, but it might be worth considering given that we're aiming to get 0.5.0 out in the nearish future.

Yes, I'd really like that ! It would also be a great achievement for me that the last months' work landed in the current release. I'll check the todos I left here and there so we can assess what is landable right now.

> Do you want to do those in a separate PR, so we can get an initial implementation landed into the next release? You don't have to, but it might be worth considering given that we're aiming to get 0.5.0 out in the nearish future. Yes, I'd really like that ! It would also be a great achievement for me that the last months' work landed in the current release. I'll check the todos I left here and there so we can assess what is landable right now.
Author
First-time contributor

@nex can you check if my mods to src/database/maps.rs are OK ? I wild-guessed the Descriptor values, I have no idea if they fit.

(Sorry, I don't know how to quote my commit's contents in Forgejo)

@nex can you check if my mods to src/database/maps.rs are OK ? I wild-guessed the `Descriptor` values, I have no idea if they fit. (Sorry, I don't know how to quote my commit's contents in Forgejo)
lafleur left a comment
Author
First-time contributor

I found out how to quote my commits in Forgejo ! see below.

I found out how to quote my commits in Forgejo ! see below.
@ -436,1 +436,4 @@
},
Descriptor {
name: "client_registrar",
..descriptor::RANDOM
Author
First-time contributor

I wild-guessed the Descriptor's contents for client_registrar and deviceid_clientidmap. Are they fit for the purpose ?

I wild-guessed the `Descriptor`'s contents for `client_registrar` and `deviceid_clientidmap`. Are they fit for the purpose ?
Owner

Both of them look okay to me -- the extra options in Descriptor are largely to optimize very hot tables.

Both of them look okay to me -- the extra options in `Descriptor` are largely to optimize very hot tables.
lafleur marked this conversation as resolved
ginger force-pushed as-oidc-provider from 9c14f246ec
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 2m25s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 6m41s
Update flake hashes / update-flake-hashes (pull_request) Successful in 12s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 10m39s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 4s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 22m24s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 17m53s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 14m16s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 5s
to 96c069cd67
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 2m29s
Update flake hashes / update-flake-hashes (pull_request) Successful in 14s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 6m24s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 6m51s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 4s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 15m12s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 14m16s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 14m16s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 4s
2025-11-11 16:44:31 +00:00
Compare
First-time contributor

Can this be used by other OIDC clients (other services able to act as OIDC clients running on the same or a different host, like CryptPad/NextCloud/OpenCloud/hopefully soon OwiCloud, Cryptomator Hub, Guacamole, EteSync, Vaultwarden+OIDC-addon etc.)? Kinda like a little substitute to Rauthy?

Can I use (configure) this now? How?

Or if not, can continuwuity be set up as a client to another OIDC provider (like Rauthy)? How?

Can this be used by other OIDC clients (other services able to act as OIDC clients running on the same or a different host, like CryptPad/NextCloud/OpenCloud/hopefully soon OwiCloud, Cryptomator Hub, Guacamole, EteSync, Vaultwarden+OIDC-addon etc.)? Kinda like a little substitute to Rauthy? Can I use (configure) this _now_? How? Or if not, can continuwuity be set up as a client to _another_ OIDC provider (like Rauthy)? How?
Author
First-time contributor

@jh72de wrote in #810 (comment):

Can this be used by other OIDC clients (other services able to act as OIDC clients running on the same or a different host, like CryptPad/NextCloud/OpenCloud/hopefully soon OwiCloud, Cryptomator Hub, Guacamole, EteSync, Vaultwarden+OIDC-addon etc.)? Kinda like a little substitute to Rauthy?

Can I use (configure) this now? How?

Or if not, can continuwuity be set up as a client to another OIDC provider (like Rauthy)? How?

Hello, this PR will let continuwuity act as a Matrix identity provider, ie a special IdP with dynamic client registration and other subtle differences with usual OIDC IdP softwares. So as such, non-matrix clients will not be able to get a token from continuwuity.

The long-term objective (for me) is to support delegating identity provision to any standard OIDC provider, like eg rauthy or kanidm. This would allow to integrate continuwuity (and probably brand it), which should make it very attractive indeed. But :

  • OIDC authorization flow in rust is implemented using the oxide-auth crate, which is a pretty sophisticated piece of software to set up
  • I'm not positive delegation to standard OIDC is even possible to implement - we depend of the matrix spec here, and no one was ever forced to be inspired :)

As a result, I'd expect a standalone implementation around soon, but delegation will need investigation and, well, work, that is, time.

@jh72de wrote in https://forgejo.ellis.link/continuwuation/continuwuity/pulls/810#issuecomment-21730: > Can this be used by other OIDC clients (other services able to act as OIDC clients running on the same or a different host, like CryptPad/NextCloud/OpenCloud/hopefully soon OwiCloud, Cryptomator Hub, Guacamole, EteSync, Vaultwarden+OIDC-addon etc.)? Kinda like a little substitute to Rauthy? > > Can I use (configure) this _now_? How? > > Or if not, can continuwuity be set up as a client to _another_ OIDC provider (like Rauthy)? How? Hello, this PR will let continuwuity act as a Matrix identity provider, ie a special IdP with dynamic client registration and other subtle differences with usual OIDC IdP softwares. So as such, non-matrix clients will not be able to get a token from continuwuity. The long-term objective (for me) is to support delegating identity provision to any standard OIDC provider, like eg rauthy or kanidm. This would allow to integrate continuwuity (and probably brand it), which should make it *very* attractive indeed. But : - OIDC authorization flow in rust is implemented using the oxide-auth crate, which is a pretty sophisticated piece of software to set up - I'm not positive delegation to standard OIDC is even possible to implement - we depend of the matrix spec here, and no one was ever *forced* to be inspired :) As a result, I'd expect a standalone implementation around soon, but delegation will need investigation and, well, work, that is, time.
First-time contributor

@lafleur wrote in #810 (comment):

  • I'm not positive delegation to standard OIDC is even possible to implement - we depend of the matrix spec here, and no one was ever forced to be inspired :)

As a result, I'd expect a standalone implementation around soon, but delegation will need investigation and, well, work, that is, time.

Maybe it helps to take a look onto how others did it in other languages? Here it's done in Python, in a basic, but working manner (serving Matrix and Element Web/X as well as other clients like NextCloud): https://github.com/Jean28518/libre-workspace/tree/main/src/usr/lib/libre-workspace/portal/idm

@lafleur wrote in https://forgejo.ellis.link/continuwuation/continuwuity/pulls/810#issuecomment-21742: > * I'm not positive delegation to standard OIDC is even possible to implement - we depend of the matrix spec here, and no one was ever _forced_ to be inspired :) > > As a result, I'd expect a standalone implementation around soon, but delegation will need investigation and, well, work, that is, time. Maybe it helps to take a look onto how others did it in other languages? Here it's done in Python, in a basic, but working manner (serving Matrix and Element Web/X as well as other clients like NextCloud): https://github.com/Jean28518/libre-workspace/tree/main/src/usr/lib/libre-workspace/portal/idm
Author
First-time contributor

Maybe it helps to take a look onto how others did it in other languages? Here it's done in Python, in a basic, but working manner (serving Matrix and Element Web/X as well as other clients like NextCloud): https://github.com/Jean28518/libre-workspace/tree/main/src/usr/lib/libre-workspace/portal/idm

I'm sorry, but to make it clear, implementing a standard OIDC identity provider inside Continuwuity is not on the agenda for me. This PR will only address Matrix clients' authorization.

Of course, when that's completed, all the authorization flows will be implemented, so you'll be free to propose another PR to let continuwuity act as a full-featured IdP.

I must say I don't think it would be a good idea though. Authorization is hard and complicated. Simply administering Kanidm will let you see that a correct implementation is non-trivial. I'm a partisan of the "do one thing and do it well" moto, and my ambition for Continuwuity is to be a complete, up-to-date Matrix server, eventually able to consume other IdP services. Not an overall IdP provider.

That's, of course, only my point of view. But as the initiator of this PR, I ask that this subject is discussed elsewhere, as it's not relevant to the work in progress here. If you want some more opinion from me, quote me in a feature request, I'll reach out as far as I can.

> Maybe it helps to take a look onto how others did it in other languages? Here it's done in Python, in a basic, but working manner (serving Matrix and Element Web/X as well as other clients like NextCloud): https://github.com/Jean28518/libre-workspace/tree/main/src/usr/lib/libre-workspace/portal/idm I'm sorry, but to make it clear, implementing a standard OIDC identity provider inside Continuwuity is not on the agenda for me. This PR will only address Matrix clients' authorization. Of course, when that's completed, all the authorization flows will be implemented, so you'll be free to propose another PR to let continuwuity act as a full-featured IdP. I must say I don't think it would be a good idea though. Authorization is hard and complicated. Simply administering Kanidm will let you see that a correct implementation is non-trivial. I'm a partisan of the "do one thing and do it well" moto, and my ambition for Continuwuity is to be a complete, up-to-date Matrix server, eventually able to consume other IdP services. Not an overall IdP provider. That's, of course, only my point of view. But as the initiator of this PR, I ask that this subject is discussed elsewhere, as it's not relevant to the work in progress here. If you want some more opinion from me, quote me in a feature request, I'll reach out as far as I can.
adds an "issuer_secret" to config.auth that lets the issuer persist tokens
between continuwuity restarts
- fixes CSP issues with localhost
- better consent message
-use askama urlencode_strict
OIDC: reimplement using rocksdb and oxide-auth-async
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 44s
Update flake hashes / update-flake-hashes (pull_request) Successful in 31s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m25s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 7m3s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 7m33s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 4s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Failing after 26s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 12m17s
Release Docker Image / Create Max-Perf Manifest (pull_request) Has been skipped
3993aa568d
devices and their tokens use the global registries and services::users commands,
and some db registries are added :
- clientid_oidcclient (stores OIDC client details)
- oidcdeviceid_grant (stores oxide-auth grant details)
- refreshtoken_userdeviceidexpiresat (stores refresh tokens' expiry date)
- userdeviceid_oidcdevice (stores OIDC device details)

This implementation lacks the owner consent dialog. This will be addressed in
a future commit.
chore: cargo +nightly fmt
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Update flake hashes / update-flake-hashes (pull_request) Successful in 12s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 43s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m38s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 5m6s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 5m12s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 11s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 11m58s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 12m45s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 9s
6abcf9d537
chore: run cargo fmt
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m8s
Update flake hashes / update-flake-hashes (pull_request) Successful in 14s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 7m39s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 7m44s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 4s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 21m26s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 13m31s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 15m10s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 4s
448408a523
Author
First-time contributor

Here is the latest batch ! Implementing specially for you, dear reader :

  • a brand new conduwuit_oidc::endpoint::OidcEndpoint tailored to Continuwuity's needs, putting together
  • a brand new conduwuit_oidc::endpoint::OidcIssuer defined over a DeviceStore trait, and
  • a simple implementation thereof in conduwuit_service::oidc::DbDeviceStore, all packed in
  • a biblically simple conduwuit_service::oidc::Service, that provides
  • oxide-auth-async's vanilla OIDC flows in src/api/client/oidc/*

One may note that login tokens are picked and stored with Continuwuity's main token ring. Other database ..er slices ? .. are added to keep track of the refresh tokens, and of the Oidc clients. The actuating is still a little messy, but the big picture is there.

I think I'm beginning to be happy with the core part (mostly the conduwuit_oidc::endpoint part). But then there are TODO marks all over the PR, that need specific solving. I'll ask for some advice on some in this discussion soon.

Also, errors are very dirty. I'd need a primer on what to pick, and what to avoid reporting. Hopefully, oxide-auth's flows really behave like black boxes and return information that is deemed secure.

Last note, I had to implement some way of tracing the fact that a user is logged in - I opted for a clear, signed cookie only containing the user's id. We could go one step further and encrypt it, so that weak clients won't even spill our user ids. Any thoughts ?

Here is the latest batch ! Implementing specially for you, dear reader : - a brand new `conduwuit_oidc::endpoint::OidcEndpoint` tailored to Continuwuity's needs, putting together - a brand new `conduwuit_oidc::endpoint::OidcIssuer` defined over a `DeviceStore` trait, and - a simple implementation thereof in `conduwuit_service::oidc::DbDeviceStore`, all packed in - a biblically simple `conduwuit_service::oidc::Service`, that provides - oxide-auth-async's vanilla OIDC flows in `src/api/client/oidc/*` One may note that login tokens are picked and stored with Continuwuity's main token ring. Other database ..er slices ? .. are added to keep track of the refresh tokens, and of the Oidc clients. The actuating is still a little messy, but the big picture is there. I think I'm beginning to be happy with the core part (mostly the `conduwuit_oidc::endpoint` part). But then there are `TODO` marks all over the PR, that need specific solving. I'll ask for some advice on some in this discussion soon. Also, errors are _very_ dirty. I'd need a primer on what to pick, and what to avoid reporting. Hopefully, oxide-auth's flows really behave like black boxes and return information that is deemed secure. Last note, I had to implement some way of tracing the fact that a user is logged in - I opted for a clear, signed cookie only containing the user's id. We could go one step further and encrypt it, so that weak clients won't even spill our user ids. Any thoughts ?
Author
First-time contributor

@nex would you care to try this new version ? I think I clarified some flow steps, and it could be more well-behaved. Connection with Fractal is bliss, with redirection in Firefox. Chromium and Epiphany both choke on the CSP thing, couldn't wrap my head around that ATM. Pretty annoying in the end.

This WIP tag is beginning to itch me a little ...

@nex would you care to try this new version ? I think I clarified some flow steps, and it could be more well-behaved. Connection with Fractal is bliss, with redirection in Firefox. Chromium and Epiphany both choke on the CSP thing, couldn't wrap my head around that ATM. Pretty annoying in the end. This WIP tag is beginning to itch me a little ...
Author
First-time contributor

Oh and I found a way to run cargo +nightly fmt, so I can do my own chores now :) Thanks for those who helped !

Oh and I found a way to run cargo +nightly fmt, so I can do my own chores now :) Thanks for those who helped !
Owner

@lafleur wrote in #810 (comment):

@nex would you care to try this new version ? I think I clarified some flow steps, and it could be more well-behaved. Connection with Fractal is bliss, with redirection in Firefox. Chromium and Epiphany both choke on the CSP thing, couldn't wrap my head around that ATM. Pretty annoying in the end.

This WIP tag is beginning to itch me a little ...

Sure! I'll drop it into a deployment later today. I'll also see which part of the CSP needs loosening.

@lafleur wrote in https://forgejo.ellis.link/continuwuation/continuwuity/pulls/810#issuecomment-21808: > @nex would you care to try this new version ? I think I clarified some flow steps, and it could be more well-behaved. Connection with Fractal is bliss, with redirection in Firefox. Chromium and Epiphany both choke on the CSP thing, couldn't wrap my head around that ATM. Pretty annoying in the end. > > This WIP tag is beginning to itch me a little ... Sure! I'll drop it into a deployment later today. I'll also see which part of the CSP needs loosening.
nex self-assigned this 2025-11-22 14:05:01 +00:00
add some docstrings
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m5s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m35s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 9m46s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 9m55s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 5s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 16m24s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 14m22s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 14m33s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 6s
82e0859e14
Owner

Still on my radar, struggling for time 😅

Still on my radar, struggling for time 😅
ginger force-pushed as-oidc-provider from 82e0859e14
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m5s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m35s
Release Docker Image / Build linux-amd64 (release) (pull_request) Successful in 9m46s
Release Docker Image / Build linux-arm64 (release) (pull_request) Successful in 9m55s
Release Docker Image / Create Multi-arch Release Manifest (pull_request) Successful in 5s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 16m24s
Release Docker Image / Build linux-amd64 (max-perf) (pull_request) Successful in 14m22s
Release Docker Image / Build linux-arm64 (max-perf) (pull_request) Successful in 14m33s
Release Docker Image / Create Max-Perf Manifest (pull_request) Successful in 6s
to f4d558283d
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m45s
Update flake hashes / update-flake-hashes (pull_request) Successful in 12s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 18m26s
2025-11-28 20:22:49 +00:00
Compare
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 2m45s
Required
Details
Update flake hashes / update-flake-hashes (pull_request) Successful in 12s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 18m26s
Required
Details
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u as-oidc-provider:lafleur-as-oidc-provider
git switch lafleur-as-oidc-provider
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
6 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
continuwuation/continuwuity!810
No description provided.