You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dynamic Client Registration hygiene for the 2026-07-28 authorization requirements (SEP-837, SEP-2207). New `resolveClientMetadata(provider)` reads `provider.clientMetadata` and applies the spec defaults — `application_type` derived from the redirect URIs (loopback or custom scheme → `'native'`, otherwise `'web'`), `grant_types: ['authorization_code', 'refresh_token']` when omitted — and `auth()` calls it once so DCR and scope selection see the same document; consumer-set values are never overwritten. DCR rejection now throws the new `RegistrationRejectedError` carrying the HTTP status, raw body, and submitted metadata — **breaking for direct `registerClient()` callers**: rejection no longer throws `OAuthError`, so update `instanceof` checks. `OAuthClientMetadata` gains a typed `application_type?: string` field (expected `'native'` / `'web'`; tolerant on parse). `OAuthErrorCode` adds `InvalidRedirectUri`. The token-exchange and refresh paths now throw the new `InsecureTokenEndpointError` for a non-`https:` token endpoint (`localhost` / `127.0.0.1` / `::1` exempt), and `auth()` surfaces it on the refresh branch instead of silently re-authorizing.
@@ -580,6 +588,10 @@ OAuth callback handling: pass the callback URL's `URLSearchParams` to `transport
580
588
581
589
`discoverAuthorizationServerMetadata()` now rejects metadata whose `issuer` does not exactly match the URL it was fetched for (RFC 8414 §3.3), throwing `IssuerMismatchError`. Pass `skipIssuerMetadataValidation: true` on `AuthOptions` (or `skipIssuerValidation: true` on the helper) only as a temporary workaround for a known-misconfigured AS.
582
590
591
+
`auth()` reads `provider.clientMetadata` once via `resolveClientMetadata()` and applies SEP-837/SEP-2207 defaults to the DCR body: `grant_types` defaults to `['authorization_code', 'refresh_token']`; `application_type` is derived from `redirect_uris` (loopback / custom URI scheme → `'native'`, otherwise `'web'`). A field you set explicitly is never overwritten — set `clientMetadata.application_type` / `clientMetadata.grant_types` to override. Direct `registerClient()` callers wanting the same defaults pass `resolveClientMetadata(provider)` as `clientMetadata`.
592
+
593
+
Token-exchange / refresh now refuse to send credentials to a non-`https:` token endpoint (loopback `localhost` / `127.0.0.1` / `::1` exempt), throwing `InsecureTokenEndpointError` with no opt-out. `auth()` surfaces this on every path including refresh — switch any plain-`http:` AS on a non-loopback host to TLS.
594
+
583
595
No code changes required; wire-behavior note: on a 2026-07-28 Streamable HTTP connection, aborting an in-flight client request (caller `signal` / timeout) closes that request's SSE response stream as the spec cancellation signal — `notifications/cancelled` is no longer POSTed
584
596
there. 2025-era connections and stdio at any era still send `notifications/cancelled`. Custom `Transport` implementations that open one underlying request per outbound message and honor `TransportSendOptions.requestSignal` may declare `readonly hasPerRequestStream = true` to opt
Copy file name to clipboardExpand all lines: docs/migration.md
+27Lines changed: 27 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -930,6 +930,33 @@ try {
930
930
}
931
931
```
932
932
933
+
### Dynamic Client Registration: `application_type` and `grant_types` defaults (SEP-837, SEP-2207)
934
+
935
+
`OAuthClientMetadata` now has a typed `application_type?: string` field (expected `'native'` / `'web'`; tolerant on parse). `auth()` resolves your provider's `clientMetadata` once via the new `resolveClientMetadata()` and uses that resolved document for both Dynamic Client Registration and scope selection. When `application_type` is unset, it is derived from your `redirect_uris`: a loopback host (`localhost` / `127.0.0.1` / `[::1]`) or a custom URI scheme yields `'native'`; anything else yields `'web'`. Set it explicitly when the heuristic is wrong for your deployment (for example a web app dev-served on `localhost`); a value you set is never overwritten.
936
+
937
+
`resolveClientMetadata()` also defaults `grant_types` to `['authorization_code', 'refresh_token']` when you omit it, so authorization servers that gate refresh-token issuance on the registered grant types issue one. If you set `grant_types` explicitly, include `'refresh_token'` yourself if you want refresh tokens. CIMD users author the hosted metadata document themselves and should include `refresh_token` there. Direct callers of `registerClient()` that want the same defaults should pass `resolveClientMetadata(provider)` as `clientMetadata`.
938
+
939
+
DCR rejection now throws `RegistrationRejectedError` (carrying `status`, `body`, and `submittedMetadata`) instead of a generic `OAuthError`. Catch it to inspect the AS's `error` / `error_description` and retry with adjusted metadata, or surface a meaningful error.
// e.submittedMetadata is exactly what was POSTed (after SDK defaults applied)
949
+
// e.body is the raw RFC 7591 error JSON from the AS
950
+
}
951
+
}
952
+
```
953
+
954
+
### Token endpoint must use TLS (SEP-2207)
955
+
956
+
`exchangeAuthorization()`, `refreshAuthorization()`, and `fetchToken()` now throw `InsecureTokenEndpointError` when the resolved token endpoint is not `https:`. Only `localhost`, `127.0.0.1`, and `::1` are exempt for local development. `auth()` surfaces this error on every path (including the refresh branch) rather than silently re-authorizing. If you were pointing at a plain-`http:` authorization server on a non-loopback host — including cluster-DNS names like `http://oauth.svc.cluster.local` or private addresses like `http://10.0.0.5` — switch it to TLS; there is no opt-out.
957
+
958
+
**Storage confidentiality remains yours.**`OAuthClientProvider.saveTokens()` receives the raw `refresh_token`; store it in platform-appropriate secure storage. The SDK guarantees transit confidentiality but cannot secure your storage layer.
959
+
933
960
### Experimental tasks interception removed
934
961
935
962
The 2025-11 experimental tasks side-channel woven through `Protocol` has been removed in preparation for the SEP-2663 Tasks Extension. The following are gone with no in-place replacement:
0 commit comments