Skip to content

Conversation

@pat-s
Copy link

@pat-s pat-s commented Dec 21, 2025

Description

Enables identity providers that require separate OIDC clients per application type (like Authentik, Kanidm, Zitadel) to work with OpenCloud clients.

  • Add desktop-specific OIDC issuer relation (http://openid.net/specs/connect/1.0/issuer/desktop)
  • Add mobile-specific OIDC issuer relation (http://openid.net/specs/connect/1.0/issuer/mobile)
  • Support optional client_id property in WebFinger link responses

Configuration

WEBFINGER_OIDC_ISSUER_DESKTOP: "https://idp.example.com"
WEBFINGER_OIDC_CLIENT_ID_DESKTOP: "desktop-client-id"
WEBFINGER_OIDC_ISSUER_MOBILE: "https://idp.example.com"
WEBFINGER_OIDC_CLIENT_ID_MOBILE: "mobile-client-id"

Motivation and Context

This problems solves opencloud-eu/desktop#246 and is a complementary PR to opencloud-eu/desktop#766.

Besides the PR for the desktop app, similar changes are needed for the iOS and Android sources.

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Technical debt
  • Tests only (no source changes)

Checklist:

  • Code changes
  • Unit tests added
  • Acceptance tests added
  • Documentation added

@kaivol
Copy link

kaivol commented Dec 21, 2025

I don't think we should allow/encourage using different OIDC issuers (and client ids) for web and desktop/mobile clients.
There really is no reason to do so, and in fact it is incorrect to assume that users from different issuers represent the same entity.


Also, I would add the OIDC scopes to request during authentication, just like it is already possible for the web client with WEB_OIDC_SCOPE. This would also fix opencloud-eu/desktop#217.

@mavgit1
Copy link

mavgit1 commented Jan 2, 2026

I don't think we should allow/encourage using different OIDC issuers (and client ids) for web and desktop/mobile clients. There really is no reason to do so, and in fact it is incorrect to assume that users from different issuers represent the same entity.

Also, I would add the OIDC scopes to request during authentication, just like it is already possible for the web client with WEB_OIDC_SCOPE. This would also fix opencloud-eu/desktop#217.

You are right that using different Issuers would break user identity (tough that is necessary to register unique urls from and idp like Authentik), but having separate Client IDs for Web and Native apps is actually standard OIDC practice.

Some IDPs (like Google Identity or Zitadel) strictly enforce this separation for security reasons (handling localhost vs https redirects) and completely refuse to mix Web and Native configurations in a single Client ID. As long as the Issuer remains the same, the user identity stays consistent.

So having the option to provide 2 different Client IDs is necessary so that Owncloud can be used with standard security practices / even work at all with some IDPs.

@kaivol
Copy link

kaivol commented Jan 3, 2026

having separate Client IDs for Web and Native apps is actually standard OIDC practice.

Could you elaborate on this point? During my use of OIDC (mostly in the self-hosting area), I never encountered such applications.
I can't think of any type of attack that would be prevented by this practice.

But anyway, if there are servers that make such requirements (different Client ID per redirect URI, IIUC), we should of course support that.
Is one Client ID for all native clients sufficient, or do we need different client for different platforms?


using different Issuers would break user identity (tough that is necessary to register unique urls from and idp like Authentik)

Could you explain what you mean by that? As far as I know, Authentik supports defining multiple redirect URIs per client.

@mavgit1
Copy link

mavgit1 commented Jan 5, 2026

having separate Client IDs for Web and Native apps is actually standard OIDC practice.

Could you elaborate on this point? During my use of OIDC (mostly in the self-hosting area), I never encountered such applications. I can't think of any type of attack that would be prevented by this practice.

image

Eg. in Zitadel you are forced to create a seperate app both for WEB and Native.

You cannot add a local redirect uri like oc://android.opencloud.eu or even http://127.0.0.1 to a WEB app. Vice versa you cannot add a normal url like https://your-domain.example.com/oidc-callback.html to a native app.

OpenCloud even reccomends having 3 seperate clients. One for Mobile App, one for Dekstop App and one for WEB. So it would be compatible with Zitadel and many others if simply the CLIENT-ID could be set manually.

using different Issuers would break user identity (tough that is necessary to register unique urls from and idp like Authentik)

Could you explain what you mean by that? As far as I know, Authentik supports defining multiple redirect URIs per client.

Yes authentik supports different URIs per client and I think even the renaming of client ID (thus being able to name the client fixed default names from OpenCloud) but each App is a different issuer URL:

See currently open issue:

goauthentik/authentik#7251

@butonic
Copy link
Contributor

butonic commented Jan 5, 2026

AFAICT there are two problems:

1. client_id registration

We try to follow OIDC best practices, which is why all of our clients have a different client_id. Each client has his own redirect urls, token lifetimes, etc. We currently hardcode these client_ids for our clients:

  • OpenCloud Web App: web
  • OpenCloud Desktop Client: OpenCloudDesktop
  • OpenCloud Android App: OpenCloudAndroid
  • OpenCloud iOS App: OpenCloudIOS
  • For more details see the Client Configuration docs.

Can Authentik, Kanidm, Zitadel and Authelia be configured to use these client_ids? If not, I would consider that a bug in them.

👀 ... yeah, Zitadel seems to assume every add developer will hardcode their generated client id in their codebase: https://zitadel.com/docs/examples/login/flutter. How is that supposed to work when an open source project develops an app and someone tries to use it with Zitadel. It seems the readonly client_id is by design: zitadel/zitadel#10149

Tip

For ADFS powershell allows setting the client_id with, eg:

Add-AdfsClient -Name "OpenCloud Desktop" -ClientId "OpenCloudDesktop" -RedirectUri "http://localhost:*"`

The spec way of getting a shared client_id (all iOS devices get OpenCloudIOS, all android devices get OpenCloudAndroid, etc) would be Dynamic Client Registration (RFC 7591) A.4.2 Client ID Shared among All Instances of Client Software, but AFAICT it would also require Software Statements: our clients would at least send a software_id property in the registration request that the IdP can use to look up the corresponding client_id. Not even keycloak supports that, yet.

Without Software Statements dynamic client registration would lead to on client per android app, which does not add any security benefits (sessions can already be killed individually) at the cost of a huge management overhead. So, Dynamic Client Registration is currently not an option, IMO.

If there are IdPs that currently do not support configuring the client_id we would have to touch all our clients and the server to dynamically look up the client_id.

Maybe the time is better spent on documenting how to configure or change the client_id with different IdPs? We had hoped that OIDC would standardize a few things ... but it seems it left out a few implementation bits. 😞

Honestly, I would prefer if admins would not have to configure anyting manually, however, either they have to configure opencloud to use the client ids generated by the IdP , or they have to configure the IdP to use our hardcoded client ids. That is, until dynamic client registration with software statements is widely supported.

2. multiple issuer urls

I guess here it is the other way around: OpenCloud currently only supports a singe OIDC issuer. Our clients discover the IdP via a GET https://cloud.opencloud.test/.well-known/openid-configuration request that we proxy to the IdP configured on the server side with OC_OIDC_ISSUER (defaults to OC_URL for the built in IdP).

When different Issuer URLs are used for different clients, where should we proxy the request to? We would have to route the request based on the user agent ... 🫨


The webfinger approach seems to be a pragmatic solution to both problems. However, there are several problems:

  1. we cannot just invent new OIDC issuer relations in the openid namespace (http://openid.net/specs/connect/1.0/issuer/desktop).
  2. we have at least four client ids: web, OpenCloudDesktop, OpenCloudAndroid, OpenCloudIOS. So we need at least four env vars to configure all of these.
  3. multiple issuers is still a problem

Tools like cyberduck or rclone will not be able to look up the configuration using webfinger because it does not follow any official spec ... but end users have to provide the client id and maybe secret on the cli anyway.

I had internally proposed to use properties in our webfinger response like this:

{
  "subject": "acct:alice@tenant.opencloud.example",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "https://idp.tenant.example.com"
    }
  ],
  "properties": {
    "client_ids": {
      "web": "opencloud-web-123",
      "desktop": "opencloud-desktop-456",
      "android": "opencloud-789",
      "ios": "opencloud-ios-abc"
    },
    "scopes": {
      "web": ["openid", "profile", "email"],
      "desktop": ["openid", "profile", "email", "roles"]
    },
    "config_url": "https://cloud.opencloud.test/config.json"
  }
}

But this does not include the issuer.

Maybe we should add a platform query parameter to the webfinger request:

GET /.well-known/webfinger?resource=https://drive.opencloud.test&platform=android

Response:
{
  "subject": "https://drive.opencloud.test",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "https://idp.example.com/tenants/acme/clients/opencloud-android"
    }
  ],
  "properties": {
    "client_id": "opencloud-android"
    "scopes": ["openid", "profile", "email"],
    "config_url": "https://cloud.opencloud.test/android-config.json"
  }
}
GET /.well-known/webfinger?resource=https://drive.opencloud.test&platform=ios

Response:
{
  "subject": "https://drive.opencloud.test",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "https://idp.example.com/tenants/acme/clients/opencloud-ios"
    }
  ],
  "properties": {
    "client_id": "opencloud-ios",
    "scopes": ["openid", "profile", "email", "roles"],
    "config_url": "https://cloud.opencloud.test/ios-config.json"
  }
}

This way:

  • we don't invent new relations
  • It is fully backwards compatible
  • every client only sees the information he requested
  • we can return the client_id
  • we can return a different issuer href if necessary
  • we can return differnet scopes the clients should request

@rhafer @micbar opinions?

@micbar
Copy link
Contributor

micbar commented Jan 5, 2026

@butonic I think your reasoning about the webfinger spec makes sense to me.

Using a platform parameter could solve this.

@butonic
Copy link
Contributor

butonic commented Jan 5, 2026

Regarding multiple issuers: I'm not sure this can work.

If the clients use different issuers, I have to assume they will receive different iss claims in the auth token / user info endpoint as well. Then the server will see four different users because the iss is different. They will not even see the same personal space ... and I am not even sure our proxy would use the issuer url from the token ... if it is a jwt, then yes. otherwise we will use the configured issuer to make a userinfo lookup ... with an access token from a different issuer ... AFAICT this is not how openid connect is supposed to work.

Maybe this works if the idp always returns the same issuer url in the userinfo endpoint, regardless of the issuer that created the access token... but that seems to be even more of a glitch then.

I might just be ignorant. Which IdP uses different issuers per client? Maybe they can give some reasoning.

And no, this has nothing to do with pairwise identifiers that creates a new sub for every relying party so they cannot crossreference user metadata - by design - for security reasons ...

@mavgit1
Copy link

mavgit1 commented Jan 5, 2026

I might just be ignorant. Which IdP uses different issuers per client? Maybe they can give some reasoning.

goauthentik/authentik#7251

this is the issue where they talk about solving that for authentik

currently i think authentik and maybe? kandim or something else have that

they just have a different and specific issuer path for every app that was registered

@pat-s
Copy link
Author

pat-s commented Jan 5, 2026

Can Authentik, Kanidm, Zitadel and Authelia be configured to use these client_ids? If not, I would consider that a bug in them.

In the overall discussion I am wondering: it reads as if (almost) all IDP tools would do this wrong (since ever) and should change and OpenCloud is having a very strong opinion on what is right or wrong for that detail specifically.

The world has seen other tools before OpenCloud which attempted to work with OIDC through desktop/web/mobile Apps.
I don't understand why this topic is filled with such strong opinions instead of working/complying with what exists (which is surely also not just a random insecure implementation by design).

On top, this topic itself should be of high importance for the overall adoption and distribution of OpenCloud itself. However, it is treated as a "maybe some day" issue for a long time already, which isn't really understandable when looking at it from a broader perspective.


PS: This is a PR. The discussion about the general issue should happen in the linked issue or a dedicated discussion thread. I'd like to know if the PR here will ever be considered or whether I should close it.

@mavgit1
Copy link

mavgit1 commented Jan 5, 2026

Why don't the Mobile / Desktop clients just request some sort of discovery json from the server?

That would not cause any further config for an enduser connecting to own cloud and the Url / https traffic is allready trusted by a CA or the user is using owncloud local only anyways. There is no security gained by hardcoding it id argue.

I think that would be a pragmatic way to solve it which also adds no complex logic to the webfinger response.

@mavgit1
Copy link

mavgit1 commented Jan 5, 2026

Also on a sidenote:

If users are in a B2B scenario where a single IDP instance exists but multiple Own Cloud instances are used, using hard-coded ID's would cause a conflict because Client_ID goes beyond an Organization in many IDP's. This is probably also the reason why you can manually set it in some and not in others.

There are two kind of approaches "islands" like eg. Keycloak or Authentik - there an Organization is isolated. Eg. multiple Relams can have the same ID i think. You'd only have an issue if you wanted the same app twice in the same realm.

And more like a "Shared" approach - eg. in Zitadel, Auth0, Google, Okta - an App can be shared across Organizations. Thus the ID must be unique and not pre-defined. 3 Organizations can use the same app with the same client_id and just be granted access to it. Thus, a pre defined ID would prevent users from adding a second instance of the same app to the entire IDP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants