From b3e31232a169c35090895aeb1981fb2d13c5a06c Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Tue, 7 Jul 2026 17:33:10 +0200 Subject: [PATCH 1/9] Add tokenExchange OAuth2 flow (RFC 8693), mirroring OAI/OpenAPI-Specification#5428 Adds tokenExchange to the pre-defined OAuth2 flow keys: tokenUrl required, scopes as for all flows. Includes the JSON Schema rule, a collection example, and a CHANGELOG entry. --- CHANGELOG.md | 7 +++++++ README.md | 10 ++++++++-- examples/collection.json | 12 ++++++++++++ json-schema/schema.json | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b8011e..9b08b52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `tokenExchange` pre-defined OAuth2 flow key for OAuth 2.0 Token Exchange + ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)), with `tokenUrl` required, + mirroring the proposed OpenAPI addition + [OAI/OpenAPI-Specification#5428](https://github.com/OAI/OpenAPI-Specification/pull/5428) + ## [v1.1.0] - 2023-04-28 ### Changed diff --git a/README.md b/README.md index 745fc69..e13728c 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ library can be described, as well as a custom signed URL authentication scheme. | `name` | string | `apiKey` | **REQUIRED.** The name of the header, query, or cookie parameter to be used. | | `in` | string | `apiKey` | **REQUIRED.** The location of the API key (`query` \| `header` \| `cookie`). | | `scheme` | string | `http` | **REQUIRED.** The name of the HTTP Authorization scheme to be used in the [Authorization header as defined in RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1). The values used SHOULD be registered in the [IANA Authentication Scheme registry](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml). (`basic` \| `bearer` \| `digest` \| `dpop` \| `hoba` \| `mutual` \| `negotiate` \| `oauth` (1.0) \| `privatetoken` \| `scram-sha-1` \| `scram-sha-256` \| `vapid`) | -| `flows` | Map | `oauth2`, `signedUrl` | **REQUIRED.** Scenarios an API client performs to get an access token from the authorization server. For `oauth2` the following keys are pre-defined for the corresponding OAuth flows: `authorizationCode` \| `implicit` \| `password ` \| `clientCredentials`. The OAuth2 Flow Object applies for `oauth2`, the Signed URL Object applies to `signedUrl`. | +| `flows` | Map | `oauth2`, `signedUrl` | **REQUIRED.** Scenarios an API client performs to get an access token from the authorization server. For `oauth2` the following keys are pre-defined for the corresponding OAuth flows: `authorizationCode` \| `implicit` \| `password ` \| `clientCredentials` \| `tokenExchange`. The OAuth2 Flow Object applies for `oauth2`, the Signed URL Object applies to `signedUrl`. | | `openIdConnectUrl` | string | `openIdConnect` | **REQUIRED.** OpenID Connect URL to discover OpenID configuration values. This MUST be in the form of a URL. | The column "Applies to" specifies for which values of `type` the fields only apply. @@ -89,11 +89,17 @@ They are also only required in this context. Based on the [OpenAPI OAuth Flow Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flows-object). Allows configuration of the supported OAuth Flows. +The `tokenExchange` flow corresponds to OAuth 2.0 Token Exchange as defined in +[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) (proposed for the OpenAPI +OAuth Flows Object in [OAI/OpenAPI-Specification#5428](https://github.com/OAI/OpenAPI-Specification/pull/5428)): +the client presents a token obtained through another scheme or flow (for example an +OpenID Connect identity token) at the `tokenUrl` and receives a different token back, +such as short-lived, scoped credentials for direct data access. | Field Name | Type | Description | | ------------------ | ----------------------- | ------------------------------------------------------------ | | `authorizationUrl` | `string` | **REQUIRED** for parent keys: `"implicit"`, `"authorizationCode"`. The authorization URL to be used for this flow. This MUST be in the form of a URL. | -| `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`. The token URL to be used for this flow. This MUST be in the form of a URL. | +| `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`, `"tokenExchange"`. The token URL to be used for this flow. This MUST be in the form of a URL. | | `scopes` | Map<`string`, `string`> | **REQUIRED.** The available scopes for the authentication scheme. A map between the scope name and a short description for it. The map MAY be empty. | | `refreshUrl` | `string` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | diff --git a/examples/collection.json b/examples/collection.json index 42d8352..58cef32 100644 --- a/examples/collection.json +++ b/examples/collection.json @@ -45,6 +45,18 @@ } } }, + "token_exchange": { + "type": "oauth2", + "description": "exchange an identity token (e.g. from an openIdConnect scheme) for short-lived, scoped credentials (OAuth 2.0 Token Exchange, RFC 8693)", + "flows": { + "tokenExchange": { + "tokenUrl": "https://example.com/credentials/token", + "scopes": { + "read:example": "Read the example data" + } + } + } + }, "signed_url_auth": { "type": "signedUrl", "description": "Requires an authentication API", diff --git a/json-schema/schema.json b/json-schema/schema.json index cd051c9..95fca86 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -298,7 +298,7 @@ "authorizationUrl" ] }, - "^(password|clientCredentials|authorizationCode)*$": { + "^(password|clientCredentials|authorizationCode|tokenExchange)*$": { "required": [ "tokenUrl" ] From 877ee12f938aca22ad5c2ce0aae3992bf784f390 Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 13 Jul 2026 19:02:14 +0200 Subject: [PATCH 2/9] Add subjectTokenScheme to the tokenExchange flow Links the exchange to the scheme that supplies its subject_token, so a generic client (e.g. STAC Browser) can resolve the order of the steps from the document instead of hardcoding it. Optional; RECOMMENDED when more than one scheme is declared. --- README.md | 3 +++ examples/collection.json | 3 ++- json-schema/schema.json | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e13728c..5a0e091 100644 --- a/README.md +++ b/README.md @@ -95,11 +95,14 @@ OAuth Flows Object in [OAI/OpenAPI-Specification#5428](https://github.com/OAI/Op the client presents a token obtained through another scheme or flow (for example an OpenID Connect identity token) at the `tokenUrl` and receives a different token back, such as short-lived, scoped credentials for direct data access. +The `subjectTokenScheme` field links the exchange to the scheme that supplies its input +token, making the multi-step flow machine-discoverable; clients MUST use it when present. | Field Name | Type | Description | | ------------------ | ----------------------- | ------------------------------------------------------------ | | `authorizationUrl` | `string` | **REQUIRED** for parent keys: `"implicit"`, `"authorizationCode"`. The authorization URL to be used for this flow. This MUST be in the form of a URL. | | `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`, `"tokenExchange"`. The token URL to be used for this flow. This MUST be in the form of a URL. | +| `subjectTokenScheme` | `string` | Applies to the parent key `"tokenExchange"`. The key of the `auth:schemes` entry whose token the client presents as the RFC 8693 `subject_token` at the `tokenUrl`. RECOMMENDED whenever more than one scheme is declared, so that a generic client can resolve the order of the steps from the document instead of hardcoding it. | | `scopes` | Map<`string`, `string`> | **REQUIRED.** The available scopes for the authentication scheme. A map between the scope name and a short description for it. The map MAY be empty. | | `refreshUrl` | `string` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | diff --git a/examples/collection.json b/examples/collection.json index 58cef32..f65a4e6 100644 --- a/examples/collection.json +++ b/examples/collection.json @@ -47,10 +47,11 @@ }, "token_exchange": { "type": "oauth2", - "description": "exchange an identity token (e.g. from an openIdConnect scheme) for short-lived, scoped credentials (OAuth 2.0 Token Exchange, RFC 8693)", + "description": "exchange the token obtained via the `oauth` scheme for short-lived, scoped credentials (OAuth 2.0 Token Exchange, RFC 8693)", "flows": { "tokenExchange": { "tokenUrl": "https://example.com/credentials/token", + "subjectTokenScheme": "oauth", "scopes": { "read:example": "Read the example data" } diff --git a/json-schema/schema.json b/json-schema/schema.json index 95fca86..1a79bf1 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -375,6 +375,10 @@ "type": "string", "format": "uri" }, + "subjectTokenScheme": { + "title": "Key of the auth:schemes entry whose token is presented as the subject_token (tokenExchange flow)", + "type": "string" + }, "refreshUrl": { "title": "The URL to be used for obtaining refresh tokens", "type": "string", From 62049e5f84f9e8b6401a1c2a43890ab7d3b64869 Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 13 Jul 2026 19:21:43 +0200 Subject: [PATCH 3/9] Reference the token_exchange scheme from an asset in the example Shows the full chain end-to-end: asset -> auth:refs -> token_exchange -> subjectTokenScheme -> oauth. Previously the scheme was declared but unreferenced. --- examples/collection.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/collection.json b/examples/collection.json index f65a4e6..8b2f39a 100644 --- a/examples/collection.json +++ b/examples/collection.json @@ -105,6 +105,17 @@ "auth:refs": [ "signed_url_auth" ] + }, + "example_exchanged": { + "href": "https://storage.example.com/private-bucket/file.xyz", + "title": "Asset read with credentials obtained via token exchange", + "type": "application/vnd.example", + "roles": [ + "data" + ], + "auth:refs": [ + "token_exchange" + ] } }, "item_assets": { From 4ee45da90c4e9fd747fb028ed92b795ac93dd528 Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 13 Jul 2026 19:31:22 +0200 Subject: [PATCH 4/9] Move the token-exchange demo to a dedicated, focused example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts examples/collection.json to its pristine state and adds examples/collection-token-exchange.json: identity scheme (oidc) + exchange scheme linked via subjectTokenScheme + two gated assets sharing one exchange. The identity scheme is intentionally unreferenced by any auth:refs — the case that motivates the field. Follows the multi-example convention of other extensions (e.g. datacube). README points to it. --- README.md | 2 + examples/collection-token-exchange.json | 81 +++++++++++++++++++++++++ examples/collection.json | 24 -------- 3 files changed, 83 insertions(+), 24 deletions(-) create mode 100644 examples/collection-token-exchange.json diff --git a/README.md b/README.md index 5a0e091..5b2cccd 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ Definition for a request parameter. ## Examples `auth:schemes` may be referenced identically in a STAC Asset or Link objects. Examples of these two use-cases are provided below. +A complete, focused example of the two-step token-exchange pattern (identity scheme + exchange scheme linked via `subjectTokenScheme`) +is provided in [examples/collection-token-exchange.json](examples/collection-token-exchange.json). ### Schema definitions diff --git a/examples/collection-token-exchange.json b/examples/collection-token-exchange.json new file mode 100644 index 0000000..95a1a25 --- /dev/null +++ b/examples/collection-token-exchange.json @@ -0,0 +1,81 @@ +{ + "type": "Collection", + "stac_version": "1.0.0", + "id": "collection-token-exchange", + "title": "Gated collection — two-step access via OAuth 2.0 Token Exchange", + "description": "Focused example of the two-step access pattern: the STAC metadata (this document) is public, while the data assets live in access-controlled object storage. Step 1: the client signs in via the `oidc` scheme and obtains an identity token. Step 2: it presents that token as the RFC 8693 `subject_token` at the `token_exchange` scheme's `tokenUrl` (declared by `subjectTokenScheme`) and receives short-lived, scoped credentials to read the assets directly. Note that the `oidc` scheme is intentionally not referenced by any `auth:refs`: it exists only as the exchange's input, which is exactly what `subjectTokenScheme` makes machine-discoverable.", + "license": "proprietary", + "stac_extensions": [ + "https://stac-extensions.github.io/authentication/v1.1.0/schema.json" + ], + "auth:schemes": { + "oidc": { + "type": "openIdConnect", + "description": "Step 1 — identity. Sign in via any OIDC client flow (e.g. Authorization Code + PKCE) to obtain an identity token.", + "openIdConnectUrl": "https://auth.example.com/.well-known/openid-configuration" + }, + "token_exchange": { + "type": "oauth2", + "description": "Step 2 — credentials (OAuth 2.0 Token Exchange, RFC 8693). POST the identity token obtained via the `oidc` scheme as `subject_token` to the `tokenUrl`; receive short-lived, scoped credentials for direct reads of this collection's assets. One exchanged credential covers all assets below.", + "flows": { + "tokenExchange": { + "tokenUrl": "https://credentials.example.com/oauth/token", + "subjectTokenScheme": "oidc", + "scopes": { + "read:data": "Read this collection's data assets" + } + } + } + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -3.9, + 40.3, + -3.5, + 40.6 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2025-01-01T00:00:00Z", + null + ] + ] + } + }, + "links": [ + { + "href": "https://example.com/examples/collection-token-exchange.json", + "rel": "self" + } + ], + "assets": { + "data": { + "href": "https://storage.example.com/private-bucket/data.parquet", + "title": "Data file (access-controlled)", + "type": "application/vnd.apache.parquet", + "roles": [ + "data" + ], + "auth:refs": [ + "token_exchange" + ] + }, + "metadata": { + "href": "https://storage.example.com/private-bucket/metadata.json", + "title": "Table metadata (access-controlled; same exchanged credentials)", + "type": "application/json", + "roles": [ + "metadata" + ], + "auth:refs": [ + "token_exchange" + ] + } + } +} diff --git a/examples/collection.json b/examples/collection.json index 8b2f39a..42d8352 100644 --- a/examples/collection.json +++ b/examples/collection.json @@ -45,19 +45,6 @@ } } }, - "token_exchange": { - "type": "oauth2", - "description": "exchange the token obtained via the `oauth` scheme for short-lived, scoped credentials (OAuth 2.0 Token Exchange, RFC 8693)", - "flows": { - "tokenExchange": { - "tokenUrl": "https://example.com/credentials/token", - "subjectTokenScheme": "oauth", - "scopes": { - "read:example": "Read the example data" - } - } - } - }, "signed_url_auth": { "type": "signedUrl", "description": "Requires an authentication API", @@ -105,17 +92,6 @@ "auth:refs": [ "signed_url_auth" ] - }, - "example_exchanged": { - "href": "https://storage.example.com/private-bucket/file.xyz", - "title": "Asset read with credentials obtained via token exchange", - "type": "application/vnd.example", - "roles": [ - "data" - ], - "auth:refs": [ - "token_exchange" - ] } }, "item_assets": { From 5720ec7bc271795b0ee52ae48a7c9a2ac484958f Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 24 Aug 2026 02:55:15 +0200 Subject: [PATCH 5/9] Require subjectTokenScheme for the tokenExchange flow The field is what makes the two-step exchange machine-discoverable: without it a client can find the tokenUrl but cannot tell which of the declared schemes produces the token it must present as the RFC 8693 subject_token. Left optional, every client has to invent its own fallback and the spec defines none, so make it required for the flow and enforce that in the schema. Also document the grant_type and the RFC 8693 response, and note that subject_token_type follows from the referenced scheme's type so it needs no field of its own. Drop the reference to OAI/OpenAPI-Specification#5428, which is parked pending the OpenAPI security spec split; RFC 8693 is the normative anchor. --- CHANGELOG.md | 7 ++++--- README.md | 27 +++++++++++++++++++-------- json-schema/schema.json | 5 +++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b08b52..7f63f9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `tokenExchange` pre-defined OAuth2 flow key for OAuth 2.0 Token Exchange - ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)), with `tokenUrl` required, - mirroring the proposed OpenAPI addition - [OAI/OpenAPI-Specification#5428](https://github.com/OAI/OpenAPI-Specification/pull/5428) + ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)), with `tokenUrl` required +- `subjectTokenScheme` field on the `tokenExchange` flow, naming the `auth:schemes` + entry whose token the client presents as the RFC 8693 `subject_token`; required for + that flow, so the multi-step exchange is discoverable from the document ## [v1.1.0] - 2023-04-28 diff --git a/README.md b/README.md index 5b2cccd..b31189d 100644 --- a/README.md +++ b/README.md @@ -90,19 +90,30 @@ They are also only required in this context. Based on the [OpenAPI OAuth Flow Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flows-object). Allows configuration of the supported OAuth Flows. The `tokenExchange` flow corresponds to OAuth 2.0 Token Exchange as defined in -[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) (proposed for the OpenAPI -OAuth Flows Object in [OAI/OpenAPI-Specification#5428](https://github.com/OAI/OpenAPI-Specification/pull/5428)): -the client presents a token obtained through another scheme or flow (for example an -OpenID Connect identity token) at the `tokenUrl` and receives a different token back, -such as short-lived, scoped credentials for direct data access. -The `subjectTokenScheme` field links the exchange to the scheme that supplies its input -token, making the multi-step flow machine-discoverable; clients MUST use it when present. +[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693). +The client presents a token obtained through another scheme (for example an OpenID +Connect identity token) at the `tokenUrl` as the `subject_token`, with +`grant_type=urn:ietf:params:oauth:grant-type:token-exchange`, and receives a different +security token back, such as short-lived, scoped credentials for direct data access. +The response is the one defined in +[RFC 8693, Section 2.2.1](https://datatracker.ietf.org/doc/html/rfc8693#section-2.2.1), +which reports the kind of token issued in `issued_token_type`. + +`subjectTokenScheme` names the scheme that supplies the input token, which is what makes +the multi-step flow machine-discoverable: without it a client can find the `tokenUrl` but +cannot tell which of the declared schemes produces the token it has to present. +Publishers MUST include it in a `tokenExchange` flow, and clients MUST use it when +present. +The RFC 8693 `subject_token_type` parameter follows from the referenced scheme's `type`, +so it needs no separate field: for example +`urn:ietf:params:oauth:token-type:id_token` for `openIdConnect`, or +`urn:ietf:params:oauth:token-type:access_token` for `oauth2`. | Field Name | Type | Description | | ------------------ | ----------------------- | ------------------------------------------------------------ | | `authorizationUrl` | `string` | **REQUIRED** for parent keys: `"implicit"`, `"authorizationCode"`. The authorization URL to be used for this flow. This MUST be in the form of a URL. | | `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`, `"tokenExchange"`. The token URL to be used for this flow. This MUST be in the form of a URL. | -| `subjectTokenScheme` | `string` | Applies to the parent key `"tokenExchange"`. The key of the `auth:schemes` entry whose token the client presents as the RFC 8693 `subject_token` at the `tokenUrl`. RECOMMENDED whenever more than one scheme is declared, so that a generic client can resolve the order of the steps from the document instead of hardcoding it. | +| `subjectTokenScheme` | `string` | **REQUIRED** for parent key: `"tokenExchange"`. The key of the `auth:schemes` entry whose token the client presents as the RFC 8693 `subject_token` at the `tokenUrl`. Lets a generic client resolve the order of the steps from the document instead of hardcoding it. | | `scopes` | Map<`string`, `string`> | **REQUIRED.** The available scopes for the authentication scheme. A map between the scope name and a short description for it. The map MAY be empty. | | `refreshUrl` | `string` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | diff --git a/json-schema/schema.json b/json-schema/schema.json index 1a79bf1..f94db21 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -302,6 +302,11 @@ "required": [ "tokenUrl" ] + }, + "^tokenExchange$": { + "required": [ + "subjectTokenScheme" + ] } } } From 91c620edf9e9df644073ea8e85a7a9ef571bfe6c Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 24 Aug 2026 02:55:15 +0200 Subject: [PATCH 6/9] Trim the token-exchange example to foreground the two edges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The descriptions narrated the flow at such length that the fields carrying it — auth:refs on the asset and subjectTokenScheme on the flow — were the least prominent thing in the document, which invited reading the chain as prose-only. Cut the prose to what no field expresses and drop the asset titles; the auth structure itself is unchanged. --- examples/collection-token-exchange.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/collection-token-exchange.json b/examples/collection-token-exchange.json index 95a1a25..403226f 100644 --- a/examples/collection-token-exchange.json +++ b/examples/collection-token-exchange.json @@ -3,7 +3,7 @@ "stac_version": "1.0.0", "id": "collection-token-exchange", "title": "Gated collection — two-step access via OAuth 2.0 Token Exchange", - "description": "Focused example of the two-step access pattern: the STAC metadata (this document) is public, while the data assets live in access-controlled object storage. Step 1: the client signs in via the `oidc` scheme and obtains an identity token. Step 2: it presents that token as the RFC 8693 `subject_token` at the `token_exchange` scheme's `tokenUrl` (declared by `subjectTokenScheme`) and receives short-lived, scoped credentials to read the assets directly. Note that the `oidc` scheme is intentionally not referenced by any `auth:refs`: it exists only as the exchange's input, which is exactly what `subjectTokenScheme` makes machine-discoverable.", + "description": "Public STAC metadata, access-controlled assets. The asset points at the scheme that guards it (`auth:refs`); that scheme points at the identity whose token it exchanges (`subjectTokenScheme`). The `oidc` scheme guards nothing on its own: it is the exchange's input.", "license": "proprietary", "stac_extensions": [ "https://stac-extensions.github.io/authentication/v1.1.0/schema.json" @@ -11,12 +11,11 @@ "auth:schemes": { "oidc": { "type": "openIdConnect", - "description": "Step 1 — identity. Sign in via any OIDC client flow (e.g. Authorization Code + PKCE) to obtain an identity token.", "openIdConnectUrl": "https://auth.example.com/.well-known/openid-configuration" }, "token_exchange": { "type": "oauth2", - "description": "Step 2 — credentials (OAuth 2.0 Token Exchange, RFC 8693). POST the identity token obtained via the `oidc` scheme as `subject_token` to the `tokenUrl`; receive short-lived, scoped credentials for direct reads of this collection's assets. One exchanged credential covers all assets below.", + "description": "RFC 8693 token exchange: present the `oidc` identity token as the `subject_token` at the `tokenUrl` and receive short-lived, scoped credentials covering every asset below.", "flows": { "tokenExchange": { "tokenUrl": "https://credentials.example.com/oauth/token", @@ -57,7 +56,6 @@ "assets": { "data": { "href": "https://storage.example.com/private-bucket/data.parquet", - "title": "Data file (access-controlled)", "type": "application/vnd.apache.parquet", "roles": [ "data" @@ -68,7 +66,6 @@ }, "metadata": { "href": "https://storage.example.com/private-bucket/metadata.json", - "title": "Table metadata (access-controlled; same exchanged credentials)", "type": "application/json", "roles": [ "metadata" From 4de5f58a75e731cd80f81bb2348a383b79920ea0 Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Mon, 31 Aug 2026 23:02:38 +0200 Subject: [PATCH 7/9] Chain via scheme-level auth:refs; add explicit subjectTokenType MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per review: the prerequisite edge moves from the flow-level subjectTokenScheme onto the scheme itself as auth:refs — reusing the reference mechanism clients already implement, and generalizing to other scheme types (a signedUrl scheme can name the scheme that authenticates its authorizationApi). A tokenExchange scheme must reference exactly one scheme, whose token is the RFC 8693 subject_token; chains are acyclic. The subject_token_type is now explicit-over-implicit: an optional subjectTokenType URN on the flow, defaulting from the referenced scheme's type when absent (OIDC yields both an id_token and an access token, so inference alone is order-dependent). --- CHANGELOG.md | 11 +++-- README.md | 44 ++++++++++++++----- examples/collection-token-exchange.json | 7 ++- json-schema/schema.json | 58 +++++++++++++++++++++---- 4 files changed, 94 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f63f9a..5577d6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `tokenExchange` pre-defined OAuth2 flow key for OAuth 2.0 Token Exchange ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)), with `tokenUrl` required -- `subjectTokenScheme` field on the `tokenExchange` flow, naming the `auth:schemes` - entry whose token the client presents as the RFC 8693 `subject_token`; required for - that flow, so the multi-step exchange is discoverable from the document +- `auth:refs` allowed on an Authentication Scheme Object, declaring prerequisite + scheme(s) whose token this scheme consumes; required with exactly one entry for a + scheme declaring a `tokenExchange` flow (the referenced scheme's token is the + RFC 8693 `subject_token`), so the multi-step exchange is discoverable from the + document; reference chains must be acyclic +- `subjectTokenType` field (optional) on the `tokenExchange` flow: the RFC 8693 + `subject_token_type` URN, for when the referenced scheme yields more than one kind + of token; defaults from the referenced scheme's `type` ## [v1.1.0] - 2023-04-28 diff --git a/README.md b/README.md index b31189d..bd953e7 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The fields in the table below can be used in these parts of STAC documents: | Field Name | Type | Description | | ----------- | ---------- | ----------- | -| `auth:refs` | \[string\] | A property that specifies which schemes in `auth:schemes` may be used to access an Asset or Link. | +| `auth:refs` | \[string\] | A property that specifies which schemes in `auth:schemes` may be used to access an Asset or Link. `auth:refs` MAY also appear on an [Authentication Scheme Object](#authentication-scheme-object) itself — nested inside `auth:schemes`, so within Catalogs, Collections and Item Properties — where it declares prerequisite scheme(s) instead — see below. | ### Scheme Types @@ -76,6 +76,7 @@ library can be described, as well as a custom signed URL authentication scheme. | ------------------ | ------------------------------------------------------------ | --------------------- | ------------------------------------------------------------ | | `type` | string | *All* | **REQUIRED**. The authentication scheme type used to access the data (`http` \| `s3` \| `signedUrl` \| `oauth2` \| `apiKey` \| `openIdConnect` \| a custom scheme type ). | | `description` | string | *All* | Additional instructions for authentication. [CommonMark 0.29](https://commonmark.org/) syntax MAY be used for rich text representation. | +| `auth:refs` | \[string\] | *All* | Keys of other entries in `auth:schemes` that are prerequisites of this scheme: the referenced scheme(s) must be completed first and supply the input token for this one. **REQUIRED with exactly one entry** for an `oauth2` scheme declaring a `tokenExchange` flow (the referenced scheme's token is the RFC 8693 `subject_token`); MAY be used by other types, e.g. a `signedUrl` scheme naming the scheme whose token authenticates requests to its `authorizationApi`. References MUST NOT form cycles. | | `name` | string | `apiKey` | **REQUIRED.** The name of the header, query, or cookie parameter to be used. | | `in` | string | `apiKey` | **REQUIRED.** The location of the API key (`query` \| `header` \| `cookie`). | | `scheme` | string | `http` | **REQUIRED.** The name of the HTTP Authorization scheme to be used in the [Authorization header as defined in RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1). The values used SHOULD be registered in the [IANA Authentication Scheme registry](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml). (`basic` \| `bearer` \| `digest` \| `dpop` \| `hoba` \| `mutual` \| `negotiate` \| `oauth` (1.0) \| `privatetoken` \| `scram-sha-1` \| `scram-sha-256` \| `vapid`) | @@ -99,26 +100,45 @@ The response is the one defined in [RFC 8693, Section 2.2.1](https://datatracker.ietf.org/doc/html/rfc8693#section-2.2.1), which reports the kind of token issued in `issued_token_type`. -`subjectTokenScheme` names the scheme that supplies the input token, which is what makes -the multi-step flow machine-discoverable: without it a client can find the `tokenUrl` but -cannot tell which of the declared schemes produces the token it has to present. -Publishers MUST include it in a `tokenExchange` flow, and clients MUST use it when -present. -The RFC 8693 `subject_token_type` parameter follows from the referenced scheme's `type`, -so it needs no separate field: for example -`urn:ietf:params:oauth:token-type:id_token` for `openIdConnect`, or -`urn:ietf:params:oauth:token-type:access_token` for `oauth2`. +Which scheme supplies the input token is declared on the *scheme*, with `auth:refs` +(see the [Authentication Scheme Object](#authentication-scheme-object)): a scheme +declaring a `tokenExchange` flow MUST reference exactly one other scheme in `auth:refs`, +and the token obtained through that referenced scheme is the `subject_token`. This is +what makes the multi-step flow machine-discoverable — a client resolves the chain from +the document (asset → guarding scheme → prerequisite scheme) instead of hardcoding the +order — and it reuses the reference mechanism clients already implement for Assets and +Links. Note the direction differs by position: on an Asset or Link, `auth:refs` lists +*alternatives* (any referenced scheme may be used); on a scheme, it lists +*prerequisites* (the referenced scheme must be completed first). References MUST NOT +form cycles — clients cannot be expected to resolve one, and the JSON Schema cannot +detect it. + +The RFC 8693 `subject_token_type` request parameter MUST be taken from the flow's +`subjectTokenType` field when present. When the field is absent it follows from the referenced +scheme's `type`: `urn:ietf:params:oauth:token-type:id_token` for `openIdConnect` and +`urn:ietf:params:oauth:token-type:access_token` for `oauth2`. Publishers SHOULD set +`subjectTokenType` explicitly whenever the referenced scheme yields more than one kind +of token (an OpenID Connect provider issues both an ID token and an access token). + +To accept identities from more than one provider, declare one exchange scheme per +identity scheme and list them all in the Asset's `auth:refs` — alternatives are +expressed at the Asset/Link level, prerequisites at the scheme level, so each exchange +scheme keeps exactly one prerequisite. | Field Name | Type | Description | | ------------------ | ----------------------- | ------------------------------------------------------------ | | `authorizationUrl` | `string` | **REQUIRED** for parent keys: `"implicit"`, `"authorizationCode"`. The authorization URL to be used for this flow. This MUST be in the form of a URL. | | `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`, `"tokenExchange"`. The token URL to be used for this flow. This MUST be in the form of a URL. | -| `subjectTokenScheme` | `string` | **REQUIRED** for parent key: `"tokenExchange"`. The key of the `auth:schemes` entry whose token the client presents as the RFC 8693 `subject_token` at the `tokenUrl`. Lets a generic client resolve the order of the steps from the document instead of hardcoding it. | +| `subjectTokenType` | `string` | For parent key `"tokenExchange"`: the RFC 8693 `subject_token_type` URN of the token presented at the `tokenUrl` (e.g. `urn:ietf:params:oauth:token-type:id_token`). When absent, it follows from the `type` of the scheme referenced in the scheme's `auth:refs`. | | `scopes` | Map<`string`, `string`> | **REQUIRED.** The available scopes for the authentication scheme. A map between the scope name and a short description for it. The map MAY be empty. | | `refreshUrl` | `string` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | ### Signed URL Object +A `signedUrl` scheme MAY declare the scheme that authenticates its `authorizationApi` +requests via `auth:refs` on the scheme (see the +[Authentication Scheme Object](#authentication-scheme-object)). + | Field Name | Type | Description | | ------------------ | -------------------------------------------------- | ------------------------------------------------------------ | | `method` | `string` | **REQUIRED.** The method to be used for requests | @@ -140,7 +160,7 @@ Definition for a request parameter. ## Examples `auth:schemes` may be referenced identically in a STAC Asset or Link objects. Examples of these two use-cases are provided below. -A complete, focused example of the two-step token-exchange pattern (identity scheme + exchange scheme linked via `subjectTokenScheme`) +A complete, focused example of the two-step token-exchange pattern (identity scheme + exchange scheme linked via scheme-level `auth:refs`) is provided in [examples/collection-token-exchange.json](examples/collection-token-exchange.json). ### Schema definitions diff --git a/examples/collection-token-exchange.json b/examples/collection-token-exchange.json index 403226f..5638fd3 100644 --- a/examples/collection-token-exchange.json +++ b/examples/collection-token-exchange.json @@ -3,7 +3,7 @@ "stac_version": "1.0.0", "id": "collection-token-exchange", "title": "Gated collection — two-step access via OAuth 2.0 Token Exchange", - "description": "Public STAC metadata, access-controlled assets. The asset points at the scheme that guards it (`auth:refs`); that scheme points at the identity whose token it exchanges (`subjectTokenScheme`). The `oidc` scheme guards nothing on its own: it is the exchange's input.", + "description": "Public STAC metadata, access-controlled assets. The asset points at the scheme that guards it (`auth:refs`); that scheme points at its prerequisite the same way (scheme-level `auth:refs`): the identity whose token it exchanges. The `oidc` scheme guards no asset on its own: it is the exchange's input.", "license": "proprietary", "stac_extensions": [ "https://stac-extensions.github.io/authentication/v1.1.0/schema.json" @@ -16,10 +16,13 @@ "token_exchange": { "type": "oauth2", "description": "RFC 8693 token exchange: present the `oidc` identity token as the `subject_token` at the `tokenUrl` and receive short-lived, scoped credentials covering every asset below.", + "auth:refs": [ + "oidc" + ], "flows": { "tokenExchange": { "tokenUrl": "https://credentials.example.com/oauth/token", - "subjectTokenScheme": "oidc", + "subjectTokenType": "urn:ietf:params:oauth:token-type:id_token", "scopes": { "read:data": "Read this collection's data assets" } diff --git a/json-schema/schema.json b/json-schema/schema.json index f94db21..e33b80a 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -84,7 +84,7 @@ } ] } - ], + ], "definitions": { "schemes_field": { "type": "object", @@ -166,6 +166,13 @@ "description": { "title": "Authentication scheme description", "type": "string" + }, + "auth:refs": { + "title": "Keys of schemes in auth:schemes that are prerequisites of this scheme (their result is this scheme's input, e.g. the subject_token of a tokenExchange flow)", + "type": "array", + "items": { + "type": "string" + } } }, "allOf": [ @@ -302,11 +309,6 @@ "required": [ "tokenUrl" ] - }, - "^tokenExchange$": { - "required": [ - "subjectTokenScheme" - ] } } } @@ -361,6 +363,39 @@ "openIdConnectUrl": false } } + }, + { + "$comment": "A tokenExchange flow consumes another scheme's token: the scheme must reference exactly one prerequisite scheme, whose token is the RFC 8693 subject_token.", + "if": { + "type": "object", + "required": [ + "flows" + ], + "properties": { + "type": { + "const": "oauth2" + }, + "flows": { + "type": "object", + "required": [ + "tokenExchange" + ] + } + } + }, + "then": { + "type": "object", + "required": [ + "auth:refs" + ], + "properties": { + "auth:refs": { + "type": "array", + "minItems": 1, + "maxItems": 1 + } + } + } } ] }, @@ -380,9 +415,14 @@ "type": "string", "format": "uri" }, - "subjectTokenScheme": { - "title": "Key of the auth:schemes entry whose token is presented as the subject_token (tokenExchange flow)", - "type": "string" + "subjectTokenType": { + "title": "RFC 8693 subject_token_type URN of the token presented at the tokenUrl (tokenExchange flow)", + "type": "string", + "format": "uri", + "examples": [ + "urn:ietf:params:oauth:token-type:id_token", + "urn:ietf:params:oauth:token-type:access_token" + ] }, "refreshUrl": { "title": "The URL to be used for obtaining refresh tokens", From ecbc111d811603625440c20ee00f4d085ae30c94 Mon Sep 17 00:00:00 2001 From: cayetanobv Date: Tue, 1 Sep 2026 13:55:02 +0200 Subject: [PATCH 8/9] Make scheme-level auth:refs one-of, matching Asset/Link semantics Per review: any one referenced scheme supplies the input token; sequences are chains of single references. tokenExchange cardinality relaxes from exactly one to at least one, multi-IdP collapses into one exchange scheme listing identity alternatives, and the subjectTokenType default resolves from the scheme actually used. --- CHANGELOG.md | 14 ++++---- README.md | 48 +++++++++++++------------ examples/collection-token-exchange.json | 2 +- json-schema/schema.json | 7 ++-- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5577d6d..c730d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,14 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `tokenExchange` pre-defined OAuth2 flow key for OAuth 2.0 Token Exchange ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)), with `tokenUrl` required -- `auth:refs` allowed on an Authentication Scheme Object, declaring prerequisite - scheme(s) whose token this scheme consumes; required with exactly one entry for a - scheme declaring a `tokenExchange` flow (the referenced scheme's token is the - RFC 8693 `subject_token`), so the multi-step exchange is discoverable from the - document; reference chains must be acyclic +- `auth:refs` allowed on an Authentication Scheme Object, listing the scheme(s) that + may supply this scheme's input — one-of semantics, matching `auth:refs` on Assets + and Links; sequences are expressed as chains of references. Required with at least + one entry for a scheme declaring a `tokenExchange` flow (the token obtained through + whichever referenced scheme was used is the RFC 8693 `subject_token`), so the + multi-step exchange is discoverable from the document; reference chains must be + acyclic - `subjectTokenType` field (optional) on the `tokenExchange` flow: the RFC 8693 `subject_token_type` URN, for when the referenced scheme yields more than one kind - of token; defaults from the referenced scheme's `type` + of token; defaults from the `type` of the referenced scheme used ## [v1.1.0] - 2023-04-28 diff --git a/README.md b/README.md index bd953e7..0183afd 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The fields in the table below can be used in these parts of STAC documents: | Field Name | Type | Description | | ----------- | ---------- | ----------- | -| `auth:refs` | \[string\] | A property that specifies which schemes in `auth:schemes` may be used to access an Asset or Link. `auth:refs` MAY also appear on an [Authentication Scheme Object](#authentication-scheme-object) itself — nested inside `auth:schemes`, so within Catalogs, Collections and Item Properties — where it declares prerequisite scheme(s) instead — see below. | +| `auth:refs` | \[string\] | A property that specifies which schemes in `auth:schemes` may be used to access an Asset or Link. `auth:refs` MAY also appear on an [Authentication Scheme Object](#authentication-scheme-object) itself — nested inside `auth:schemes`, so within Catalogs, Collections and Item Properties — where it declares which schemes may supply this scheme's input — see below. | ### Scheme Types @@ -76,7 +76,7 @@ library can be described, as well as a custom signed URL authentication scheme. | ------------------ | ------------------------------------------------------------ | --------------------- | ------------------------------------------------------------ | | `type` | string | *All* | **REQUIRED**. The authentication scheme type used to access the data (`http` \| `s3` \| `signedUrl` \| `oauth2` \| `apiKey` \| `openIdConnect` \| a custom scheme type ). | | `description` | string | *All* | Additional instructions for authentication. [CommonMark 0.29](https://commonmark.org/) syntax MAY be used for rich text representation. | -| `auth:refs` | \[string\] | *All* | Keys of other entries in `auth:schemes` that are prerequisites of this scheme: the referenced scheme(s) must be completed first and supply the input token for this one. **REQUIRED with exactly one entry** for an `oauth2` scheme declaring a `tokenExchange` flow (the referenced scheme's token is the RFC 8693 `subject_token`); MAY be used by other types, e.g. a `signedUrl` scheme naming the scheme whose token authenticates requests to its `authorizationApi`. References MUST NOT form cycles. | +| `auth:refs` | \[string\] | *All* | Keys of other entries in `auth:schemes` that may supply this scheme's input: any *one* of the referenced schemes is completed first, and the token it yields is the input to this one. **REQUIRED with at least one entry** for an `oauth2` scheme declaring a `tokenExchange` flow (the token obtained through whichever referenced scheme was used is the RFC 8693 `subject_token`); MAY be used by other types, e.g. a `signedUrl` scheme naming the scheme(s) whose token authenticates requests to its `authorizationApi`. References MUST NOT form cycles. | | `name` | string | `apiKey` | **REQUIRED.** The name of the header, query, or cookie parameter to be used. | | `in` | string | `apiKey` | **REQUIRED.** The location of the API key (`query` \| `header` \| `cookie`). | | `scheme` | string | `http` | **REQUIRED.** The name of the HTTP Authorization scheme to be used in the [Authorization header as defined in RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1). The values used SHOULD be registered in the [IANA Authentication Scheme registry](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml). (`basic` \| `bearer` \| `digest` \| `dpop` \| `hoba` \| `mutual` \| `negotiate` \| `oauth` (1.0) \| `privatetoken` \| `scram-sha-1` \| `scram-sha-256` \| `vapid`) | @@ -102,41 +102,45 @@ which reports the kind of token issued in `issued_token_type`. Which scheme supplies the input token is declared on the *scheme*, with `auth:refs` (see the [Authentication Scheme Object](#authentication-scheme-object)): a scheme -declaring a `tokenExchange` flow MUST reference exactly one other scheme in `auth:refs`, -and the token obtained through that referenced scheme is the `subject_token`. This is -what makes the multi-step flow machine-discoverable — a client resolves the chain from -the document (asset → guarding scheme → prerequisite scheme) instead of hardcoding the -order — and it reuses the reference mechanism clients already implement for Assets and -Links. Note the direction differs by position: on an Asset or Link, `auth:refs` lists -*alternatives* (any referenced scheme may be used); on a scheme, it lists -*prerequisites* (the referenced scheme must be completed first). References MUST NOT -form cycles — clients cannot be expected to resolve one, and the JSON Schema cannot -detect it. +declaring a `tokenExchange` flow MUST reference at least one other scheme in +`auth:refs`; the client completes any *one* of the referenced schemes, and the token +obtained through it is the `subject_token`. This is what makes the multi-step flow +machine-discoverable — a client resolves the chain from the document (asset → guarding +scheme → input scheme) instead of hardcoding the order — and it reuses the reference +mechanism clients already implement for Assets and Links, with the same one-of +semantics in both positions: on an Asset or Link the referenced schemes are alternative +ways to access the resource, on a scheme they are alternative ways to obtain its input. +A sequence of steps is expressed as a chain — each scheme referencing the one before +it — not as multiple entries in one list. References MUST NOT form cycles — clients +cannot be expected to resolve one, and the JSON Schema cannot detect it. The RFC 8693 `subject_token_type` request parameter MUST be taken from the flow's -`subjectTokenType` field when present. When the field is absent it follows from the referenced -scheme's `type`: `urn:ietf:params:oauth:token-type:id_token` for `openIdConnect` and +`subjectTokenType` field when present. When the field is absent it follows from the +`type` of the referenced scheme the client used: +`urn:ietf:params:oauth:token-type:id_token` for `openIdConnect` and `urn:ietf:params:oauth:token-type:access_token` for `oauth2`. Publishers SHOULD set -`subjectTokenType` explicitly whenever the referenced scheme yields more than one kind +`subjectTokenType` explicitly whenever a referenced scheme yields more than one kind of token (an OpenID Connect provider issues both an ID token and an access token). +Since the field applies to the flow as a whole, referenced alternatives requiring +*different* `subject_token_type` values SHOULD be split into separate exchange +schemes. -To accept identities from more than one provider, declare one exchange scheme per -identity scheme and list them all in the Asset's `auth:refs` — alternatives are -expressed at the Asset/Link level, prerequisites at the scheme level, so each exchange -scheme keeps exactly one prerequisite. +To accept identities from more than one provider, list the identity schemes as +alternatives in the exchange scheme's own `auth:refs` — a token obtained through any +one of them is exchanged at the same `tokenUrl`. | Field Name | Type | Description | | ------------------ | ----------------------- | ------------------------------------------------------------ | | `authorizationUrl` | `string` | **REQUIRED** for parent keys: `"implicit"`, `"authorizationCode"`. The authorization URL to be used for this flow. This MUST be in the form of a URL. | | `tokenUrl` | `string` | **REQUIRED** for parent keys: `"password"`, `"clientCredentials"`, `"authorizationCode"`, `"tokenExchange"`. The token URL to be used for this flow. This MUST be in the form of a URL. | -| `subjectTokenType` | `string` | For parent key `"tokenExchange"`: the RFC 8693 `subject_token_type` URN of the token presented at the `tokenUrl` (e.g. `urn:ietf:params:oauth:token-type:id_token`). When absent, it follows from the `type` of the scheme referenced in the scheme's `auth:refs`. | +| `subjectTokenType` | `string` | For parent key `"tokenExchange"`: the RFC 8693 `subject_token_type` URN of the token presented at the `tokenUrl` (e.g. `urn:ietf:params:oauth:token-type:id_token`). When absent, it follows from the `type` of the scheme in the scheme's `auth:refs` through which the token was obtained. | | `scopes` | Map<`string`, `string`> | **REQUIRED.** The available scopes for the authentication scheme. A map between the scope name and a short description for it. The map MAY be empty. | | `refreshUrl` | `string` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | ### Signed URL Object -A `signedUrl` scheme MAY declare the scheme that authenticates its `authorizationApi` -requests via `auth:refs` on the scheme (see the +A `signedUrl` scheme MAY declare the scheme(s) through which its `authorizationApi` +requests can be authenticated via `auth:refs` on the scheme (see the [Authentication Scheme Object](#authentication-scheme-object)). | Field Name | Type | Description | diff --git a/examples/collection-token-exchange.json b/examples/collection-token-exchange.json index 5638fd3..0c49547 100644 --- a/examples/collection-token-exchange.json +++ b/examples/collection-token-exchange.json @@ -3,7 +3,7 @@ "stac_version": "1.0.0", "id": "collection-token-exchange", "title": "Gated collection — two-step access via OAuth 2.0 Token Exchange", - "description": "Public STAC metadata, access-controlled assets. The asset points at the scheme that guards it (`auth:refs`); that scheme points at its prerequisite the same way (scheme-level `auth:refs`): the identity whose token it exchanges. The `oidc` scheme guards no asset on its own: it is the exchange's input.", + "description": "Public STAC metadata, access-controlled assets. The asset points at the scheme that guards it (`auth:refs`); that scheme points the same way (scheme-level `auth:refs`) at the identity scheme(s) whose token it exchanges — any one of them. The `oidc` scheme guards no asset on its own: it is the exchange's input.", "license": "proprietary", "stac_extensions": [ "https://stac-extensions.github.io/authentication/v1.1.0/schema.json" diff --git a/json-schema/schema.json b/json-schema/schema.json index e33b80a..f46339e 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -168,7 +168,7 @@ "type": "string" }, "auth:refs": { - "title": "Keys of schemes in auth:schemes that are prerequisites of this scheme (their result is this scheme's input, e.g. the subject_token of a tokenExchange flow)", + "title": "Keys of schemes in auth:schemes that may supply this scheme's input (any one of them is completed first; its result is this scheme's input, e.g. the subject_token of a tokenExchange flow)", "type": "array", "items": { "type": "string" @@ -365,7 +365,7 @@ } }, { - "$comment": "A tokenExchange flow consumes another scheme's token: the scheme must reference exactly one prerequisite scheme, whose token is the RFC 8693 subject_token.", + "$comment": "A tokenExchange flow consumes another scheme's token: the scheme must reference at least one scheme; the token obtained through whichever one the client uses is the RFC 8693 subject_token.", "if": { "type": "object", "required": [ @@ -391,8 +391,7 @@ "properties": { "auth:refs": { "type": "array", - "minItems": 1, - "maxItems": 1 + "minItems": 1 } } } From 2d05232810e074123cc2e51d6dd5e4efa337f4ed Mon Sep 17 00:00:00 2001 From: Matthias Mohr Date: Tue, 1 Sep 2026 22:02:36 +0900 Subject: [PATCH 9/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0183afd..5c1d5bd 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ library can be described, as well as a custom signed URL authentication scheme. | `name` | string | `apiKey` | **REQUIRED.** The name of the header, query, or cookie parameter to be used. | | `in` | string | `apiKey` | **REQUIRED.** The location of the API key (`query` \| `header` \| `cookie`). | | `scheme` | string | `http` | **REQUIRED.** The name of the HTTP Authorization scheme to be used in the [Authorization header as defined in RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1). The values used SHOULD be registered in the [IANA Authentication Scheme registry](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml). (`basic` \| `bearer` \| `digest` \| `dpop` \| `hoba` \| `mutual` \| `negotiate` \| `oauth` (1.0) \| `privatetoken` \| `scram-sha-1` \| `scram-sha-256` \| `vapid`) | -| `flows` | Map | `oauth2`, `signedUrl` | **REQUIRED.** Scenarios an API client performs to get an access token from the authorization server. For `oauth2` the following keys are pre-defined for the corresponding OAuth flows: `authorizationCode` \| `implicit` \| `password ` \| `clientCredentials` \| `tokenExchange`. The OAuth2 Flow Object applies for `oauth2`, the Signed URL Object applies to `signedUrl`. | +| `flows` | Map | `oauth2`, `signedUrl` | **REQUIRED.** Scenarios an API client performs to get an access token from the authorization server. For `oauth2` the following keys are pre-defined for the corresponding OAuth flows: `authorizationCode` \| `implicit` \| `password` \| `clientCredentials` \| `tokenExchange`. The OAuth2 Flow Object applies for `oauth2`, the Signed URL Object applies to `signedUrl`. | | `openIdConnectUrl` | string | `openIdConnect` | **REQUIRED.** OpenID Connect URL to discover OpenID configuration values. This MUST be in the form of a URL. | The column "Applies to" specifies for which values of `type` the fields only apply.