docs: document the OIDC audience parameter - #137
oc-tmueller wants to merge 3 commits into
Conversation
The openidconnect app gains an optional "audience" key naming the value the IdP puts into the access token's "aud" claim. It defaults to client-id, and is needed by IdPs that address the resource server instead - RFC 9068 §3 defines an access token's "aud" that way, and Microsoft ADFS follows it, prefixing the application identifier with "microsoft:identityserver:" unless that identifier is already a URL. Documented for 11.0 and 10.16, the two versions the app change ships on. The entry covers the operational consequences rather than just the syntax, because each of them is a way to lock an instance out: the audience becomes authoritative once set, so a token issued to another client of the same IdP is accepted when its "aud" matches, an introspection response that omits "aud" can no longer be used at all, and with token-exchange mode the first list entry is what gets requested from the IdP. Values that cannot be an audience are discarded, and if none is left every access token is rejected. For finding the ADFS value, both cmdlets are named: Get-AdfsWebApiApplication for an OpenID Connect application group, Get-AdfsRelyingPartyTrust for a legacy WS-Federation or SAML trust. Naming only the latter would strand admins whose OIDC registration is an application group, which is the modern default. No app version numbers are claimed: neither release carrying the fix is tagged yet, so the entry points at the issue instead. See owncloud/openidconnect#373 and owncloud/openidconnect#374 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
|
Converted to draft — do not merge as-is. I authored this by hand, and this page is generated.
The pipeline is live, not dead — core changelog What this PR becomes
Verified in the meantime: both pages here are currently byte-in-sync with core, so the regeneration will add only the new entry and no unrelated drift. Two side findings, each getting its own PR: 10.16's sibling page |
The README claimed that because another client of the same IdP can often get ownCloud's identifier into "aud" - its own audience mapper, an RFC 8707 resource parameter - the "audience" key is worth setting for that reason too. That is backwards. In exactly that scenario the token's "aud" names ownCloud, so it is accepted whether or not the key is set; setting it changes nothing there, and additionally stops the client-naming claims from being consulted. What the key actually buys is a binding to the resource: a token ownCloud's own client obtained for some *other* resource stops authenticating here. Which clients an IdP may issue ownCloud-audience tokens to is a decision in the IdP, and no ownCloud setting can override it. The three paragraphs are rewritten as one sequence - what it buys, what it does not, what holds when it is unset - rather than two passes over the same two facts, and the Keycloak sentence now sits in the paragraph it belongs to instead of running into the end of the previous one. Same content on the admin manual side (owncloud/docs.owncloud.com#137). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
The README claimed that because another client of the same IdP can often get ownCloud's identifier into "aud" - its own audience mapper, an RFC 8707 resource parameter - the "audience" key is worth setting for that reason too. That is backwards. In exactly that scenario the token's "aud" names ownCloud, so it is accepted whether or not the key is set; setting it changes nothing there, and additionally stops the client-naming claims from being consulted. What the key actually buys is a binding to the resource: a token ownCloud's own client obtained for some *other* resource stops authenticating here. Which clients an IdP may issue ownCloud-audience tokens to is a decision in the IdP, and no ownCloud setting can override it. Documented as such now, on the admin manual side too (owncloud/docs.owncloud.com#137). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> (cherry picked from commit 2928e3c69eeaa613cfa25314efda09add16257ad)
The audience parameter alone does not tell an admin whether they need it, and for one supported provider it cannot help at all: Keycloak sends no aud claim unless an audience mapper is configured, so no configured value can ever match. openidconnect 2.4.2 and 2.3.5 therefore also accept the claim naming the client a token was issued to - azp, appid or client_id - and that is what these pages now describe. - oidc.adoc gains an "Access Token Audience" section. Because the behaviour differs per app version and both fixing releases are still unreleased, the applicability is structural rather than a footnote: the table has one column per version - "On 2.4.1" and "On 2.4.2" for ownCloud 11, "On 2.3.4 and earlier" and "On 2.3.5" for ownCloud 10 - so a reader of any single row sees what applies to the version they actually run. On 2.4.1 that means Keycloak needs the audience mapper, Azure needs requestedAccessTokenVersion 2, and ADFS and OneLogin have no remedy short of the upgrade. The section also covers both log lines an admin will meet, the refusal of tokens marked as refresh tokens, the deliberate exception for ID tokens, and the Keycloak audience-mapper recipe with its console path and kcadm.sh command. - config_apps_sample_php_parameters.adoc: the audience entry described the default as "the client-id", which is only half of it, and ended in a placeholder instead of a version. Both fixed, with the versions marked as in preparation since neither 2.4.2 nor 2.3.5 is tagged. - ms-azure-setup.adoc: requestedAccessTokenVersion decides whether aud holds the Application ID URI (v1.0 tokens, the default) or the client id (v2.0). On openidconnect 2.4.1 that decides whether the documented setup works at all, which this walkthrough never said. Each table row records whether it was observed or taken from vendor documentation; PingFederate and cidaas are marked undetermined rather than guessed, and the ownCloud 10 page says so where it would otherwise promise that no upgrade can lock a provider out. Two review rounds folded in. The claims that a token issued to a different client is "rejected either way" and that "an attacker's own client cannot get a token through either check" were both wrong and both contradicted elsewhere in the same section: the audience comparison cannot tell which client asked for a token that names ownCloud. The recommendation to set audience *because* another client might target ownCloud was inverted for the same reason - in that scenario the key changes nothing and removes the client-claim check; it binds the resource, not the client, and the pages now say which of the two they mean. Also: the Keycloak workaround was addressed to ownCloud 10 admins who cannot run 2.4.1 at all; the Azure snippet used the client-id placeholder where the App ID URI belongs, which would have rejected every token once audience was set; and the Azure manifest path read Manifest > Manage instead of Manage > Manifest.A third round corrected the ID-token statement, which claimed to hold "independently of the audience". It does not: with audience set to anything other than the client-id - what ADFS, Azure v1.0 and OneLogin need - an ID token's aud no longer matches and the client-claim fallback is suppressed, so ID tokens are rejected. That is a real benefit of the key and the pages now list it. Also in that round: the ownCloud 11 entry's lead described 2.4.2 behaviour in the present tense while 2.4.1 is what ships; the Keycloak 2.4.2 cell said audience "cannot be used" without allowing for an install that followed the 2.4.1 instruction and added the mapper; OneLogin was missing from the admonition that lists who is affected; the Azure note called the suppressed claim "the appid fallback" where v2.0 tokens use azp; and neither page said that on 2.4.1 the check reaches JWT access tokens only, so an install using opaque tokens with introspection is not affected at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
…iting them config_apps_sample_php_parameters.adoc is generated from core's config/config.apps.sample.php by owncloud/config-to-docs, which the audience entry on this branch did not account for: it existed only here, so the next regeneration would have deleted it. The text now lives in core - one commit per server line - and these two pages are that generator's output. Confirmed before regenerating that both pages were byte-identical to what the generator produces from their respective core branches, so this diff is exactly the new entries and nothing else, and running the generator again is a no-op. Five keys arrive with it that the app has always read and neither page documented: exchange-token-mode-before-introspection, use-access-token-introspection-for-user-info, and the three ocis-routing-policy-* keys. The audience entry is shortened in the move, from ten paragraphs to five. A config sample entry is read in the PHP file as well as in the manual, and the long-form discussion belongs in the hand-written Access Token Audience section, which this entry now links to per server version. Two things it had picked up are gone from here: the refresh-token rule, which is not a property of this key, and the ID-token consequence stated twice. Corrections from review, all verified against the app code: the 11.0 text says the 2.4.1 lockout applies to JWT access tokens (2.4.1 does not check the audience on the introspection path at all), the 10.16 text no longer claims the upgrade cannot lock anyone out (an introspection response with neither "aud" nor "client_id" is rejected), and the client-claim acceptance is version-qualified inline rather than only in the closing paragraph. oidc.adoc and ms-azure-setup.adoc are hand-authored pages and are untouched here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
|
The parameter-reference pages in this PR are now generator output, not hand-edited: the That matters because Verified before regenerating that both pages were byte-identical to what the generator produces from their respective core branches, so the diff here is exactly the new entries. Five keys arrive with
|
Documents the
audiencekey the openidconnect app gains in owncloud/openidconnect#374 (fixes owncloud/openidconnect#373).Why
An access token is accepted only if it names the ownCloud relying party. Until now the expected value was always the configured
client-id— which is the ID token rule (OpenID Connect Core 1.0 §2), not the access-token one. RFC 9068 §3 defines an access token'saudas the resource server, so providers that address the resource send something else entirely and could not authenticate.Microsoft ADFS is the case that made this necessary. It takes the identifier of the relying party trust and prefixes it with
microsoft:identityserver:unless that identifier is already a URL — so an admin whose relying party identifier is their client-id GUID seesaud: "microsoft:identityserver:<guid>"and has nothing to configure. ADFS is already listed as a supported IdP inconfiguration/user/oidc/oidc.adoc, so this gap was reachable from a documented setup.What
Adds an
audience::entry to the OIDC parameter reference inconfig_apps_sample_php_parameters.adoc(the page bothoidc.adocandkopano-setup.adocxref for the full key list), for the two versions the app change ships on:content/server/11.0/...— app 2.4.2content/server/10.16/...— app 2.3.5The entry covers the default (
client-id), the accepted shapes, that it replaces rather than extends the client-id, and how to find the ADFS value.It deliberately documents the operational consequences rather than just the syntax, because each one is a way to take an instance offline:
audmatches — the RFC 7662client_idcheck no longer applies. The entry says to pick a value only ownCloud can be issued for, and not to reuse a tenant-wide resource identifier.aud(which RFC 7662 permits), because every opaque token would then be rejected.exchange-token-mode-before-introspection, the first usable list entry is also what the token exchange requests from the IdP.Two deliberate choices:
Both ADFS cmdlets are named.
Get-AdfsWebApiApplicationfor an OpenID Connect application group,Get-AdfsRelyingPartyTrustfor a legacy WS-Federation or SAML trust. Naming only the latter — as the first draft did — would strand admins whose OIDC registration is an application group, which is the modern default on ADFS 2016+.No app version is claimed. Neither release carrying the fix is tagged yet (tags stop at
v2.4.1; the oC11 change sits under## [Unreleased]), so the entry points at the issue instead of asserting a number that could be off by a release.Placed alphabetically between
allowed-user-backendsandauth-params. The two files' entries are byte-identical.Checks
Full local CI equivalent —
npm ci,npm run antora,npm test— all pass, and the built pages carry the entry in both versions.Rendered output confirms the entry is a proper definition term in the right position:
Note this is the file's first use of
+list continuation (the entry needs three paragraphs). Verified in the rendered HTML that all three attach toaudienceand that every following term still parses as its own<dt>.Every factual claim was checked line-by-line against the implementation in owncloud/openidconnect#374 rather than against its README alone.
Docs-only; no nav or xref changes.
🤖 Generated with Claude Code