Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, ([OAuth2 Flow Object](#oauth2-flow-object)\|[Signed URL Object](#signed-url-object))> | `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<string, ([OAuth2 Flow Object](#oauth2-flow-object)\|[Signed URL Object](#signed-url-object))> | `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.
Expand All @@ -89,11 +89,20 @@ 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.

| 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. |
| `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. |

Expand All @@ -120,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

Expand Down
81 changes: 81 additions & 0 deletions examples/collection-token-exchange.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
}
6 changes: 5 additions & 1 deletion json-schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@
"authorizationUrl"
]
},
"^(password|clientCredentials|authorizationCode)*$": {
"^(password|clientCredentials|authorizationCode|tokenExchange)*$": {
"required": [
"tokenUrl"
]
Expand Down Expand Up @@ -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",
Expand Down