@hawcx/oauth-client 5.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +479 -0
- package/README.md +75 -10
- package/dist/client-assertion.d.ts.map +1 -1
- package/dist/client-assertion.js +6 -2
- package/dist/client-assertion.js.map +1 -1
- package/dist/delegation/exceptions.d.ts +34 -0
- package/dist/delegation/exceptions.d.ts.map +1 -1
- package/dist/delegation/exceptions.js +39 -1
- package/dist/delegation/exceptions.js.map +1 -1
- package/dist/delegation/hawcx.d.ts +6 -2
- package/dist/delegation/hawcx.d.ts.map +1 -1
- package/dist/delegation/hawcx.js.map +1 -1
- package/dist/delegation/index.d.ts +2 -1
- package/dist/delegation/index.d.ts.map +1 -1
- package/dist/delegation/index.js +3 -1
- package/dist/delegation/index.js.map +1 -1
- package/dist/delegation/transport.d.ts +6 -2
- package/dist/delegation/transport.d.ts.map +1 -1
- package/dist/delegation/transport.js +9 -2
- package/dist/delegation/transport.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/url.d.ts +66 -0
- package/dist/internal/url.d.ts.map +1 -0
- package/dist/internal/url.js +155 -0
- package/dist/internal/url.js.map +1 -0
- package/dist/management/jwt_transport.d.ts +150 -0
- package/dist/management/jwt_transport.d.ts.map +1 -0
- package/dist/management/jwt_transport.js +245 -0
- package/dist/management/jwt_transport.js.map +1 -0
- package/dist/management/response_signature.d.ts +65 -0
- package/dist/management/response_signature.d.ts.map +1 -0
- package/dist/management/response_signature.js +170 -0
- package/dist/management/response_signature.js.map +1 -0
- package/dist/oauth.d.ts +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +35 -24
- package/dist/oauth.js.map +1 -1
- package/dist/stepup/client.d.ts +72 -2
- package/dist/stepup/client.d.ts.map +1 -1
- package/dist/stepup/client.js +69 -0
- package/dist/stepup/client.js.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [6.0.0] - 2026-10-10
|
|
11
|
+
|
|
12
|
+
First public release since 5.2.0. **Major version** because of the BREAKING
|
|
13
|
+
entries below, which change behaviour for configurations that 5.2.0 accepted.
|
|
14
|
+
It contains everything from the internal release candidates 6.0.0-rc.1 and
|
|
15
|
+
6.0.0-rc.2, plus one fix to `ClientAssertionSigner` made after rc.2.
|
|
16
|
+
|
|
17
|
+
### Breaking — action needed when upgrading from 5.2.0
|
|
18
|
+
|
|
19
|
+
- **Management API response signatures are verified by default
|
|
20
|
+
(TOB-HSDK-11).** `JwtBearerTransport` and `StepUpClient.withPrivateKeyJwt`
|
|
21
|
+
now verify `X-Response-Signature` on every successful response. This
|
|
22
|
+
reverses the 5.2.0 note that callers "may" verify the header themselves.
|
|
23
|
+
The SDK checks the following:
|
|
24
|
+
- the JWS uses ES256, ES384 or ES512 and verifies against
|
|
25
|
+
`${issuer}/.well-known/jwks.json`;
|
|
26
|
+
- `iat` is within `clockSkewSeconds` (default 300);
|
|
27
|
+
- `body_sha256` matches the exact response bytes;
|
|
28
|
+
- the token carries no `aud`, `sub` or `nonce`.
|
|
29
|
+
|
|
30
|
+
Responses with status 400 and above are not verified. hx_auth signs every
|
|
31
|
+
jwt-mode 2xx, so production traffic is unaffected. **Action needed** if any
|
|
32
|
+
of these apply:
|
|
33
|
+
- A gateway, CDN or proxy strips response headers. Every call fails with
|
|
34
|
+
`ResponseSignatureInvalidError`; let `X-Response-Signature` through.
|
|
35
|
+
- Mocks, stubs or contract-test harnesses built against 5.2.0 return
|
|
36
|
+
unsigned 2xx responses. Sign the responses, or disable verification in the
|
|
37
|
+
test harness.
|
|
38
|
+
- `baseUrl` is not the OP host, such as an internal service URL or local dev
|
|
39
|
+
with separate ports. The JWKS is fetched from `baseUrl` by default, so set
|
|
40
|
+
`issuer`.
|
|
41
|
+
- **`baseUrl` (and `issuer`) values that used to be accepted now throw at
|
|
42
|
+
construction (TOB-HSDK-13).** The affected classes are `JwtBearerTransport`
|
|
43
|
+
and `StepUpClient.withPrivateKeyJwt` (`DelegationRequestError`),
|
|
44
|
+
`DelegationTransport` and the `DelegationClient`/`StepUpClient` ECIES
|
|
45
|
+
factories (`DelegationRequestError`), legacy `HawcxOAuth`
|
|
46
|
+
(`HawcxOAuthError`), and `HawcxOAuth.fromIssuer` (`DiscoveryError`):
|
|
47
|
+
- **Plain `http:` on a non-loopback host.** Examples:
|
|
48
|
+
`http://hawcx-api:8080` (docker-compose service name),
|
|
49
|
+
`http://0.0.0.0:8080`, `http://host.docker.internal:8080`, and in-cluster
|
|
50
|
+
service URLs behind a TLS-terminating gateway. Only `localhost`,
|
|
51
|
+
`127.0.0.1` and `[::1]` may use `http:`. **Action needed:** use `https:`,
|
|
52
|
+
or point the SDK at a loopback address.
|
|
53
|
+
- **Userinfo, query or fragment in the base.** For example
|
|
54
|
+
`https://user:pw@api.hawcx.com`, `https://api.hawcx.com?tenant=x` or
|
|
55
|
+
`https://api.hawcx.com#x`. **Action needed:** remove them.
|
|
56
|
+
- **The signed JWT `aud` string changes for non-canonical base spellings
|
|
57
|
+
(TOB-HSDK-13).** Host case and default ports are now normalised, so
|
|
58
|
+
`baseUrl: 'https://API.Hawcx.com:443'` produces
|
|
59
|
+
`aud = https://api.hawcx.com/v1/...`, where 5.2.0 produced
|
|
60
|
+
`https://API.Hawcx.com:443/v1/...`. The new value is the one `fetch`
|
|
61
|
+
actually sends. **Action needed** only if a server compares `aud` by exact
|
|
62
|
+
string against a configured non-canonical value: update that value, or use
|
|
63
|
+
a canonical `baseUrl`. Canonical bases (lower-case host, no default port,
|
|
64
|
+
with or without a trailing slash or a path prefix) produce byte-identical
|
|
65
|
+
URLs and `aud`.
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- New options on `JwtBearerTransport` and `StepUpClient.withPrivateKeyJwt`:
|
|
70
|
+
`issuer` (defaults to `baseUrl`), `verifyResponseSignature` (defaults to
|
|
71
|
+
`true`) and `clockSkewSeconds`. `verifyResponseSignature: false` is an
|
|
72
|
+
**emergency escape hatch** that restores the 5.2.0 behaviour and emits a
|
|
73
|
+
one-time process warning. `withPrivateKeyJwt` now also passes
|
|
74
|
+
`clockSkewSeconds` through to the transport.
|
|
75
|
+
- New error classes, both subclasses of `DelegationResponseError`, exported
|
|
76
|
+
with a stable `code`:
|
|
77
|
+
- `ResponseSignatureInvalidError` (`response_signature_invalid`).
|
|
78
|
+
- `ResponseSignatureUnavailableError` (`response_signature_unavailable`).
|
|
79
|
+
It means the signing keys could not be fetched, and **the request may
|
|
80
|
+
already have been applied** server-side.
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
|
|
84
|
+
- Every security-relevant URL is now parsed and joined with the WHATWG `URL`
|
|
85
|
+
API rather than by string concatenation (TOB-HSDK-13). This covers
|
|
86
|
+
`JwtBearerTransport` and `DelegationTransport` (`baseUrl` + endpoint),
|
|
87
|
+
legacy `new HawcxOAuth({ baseUrl })` (`/oauth2/token` and `/keys`), and the
|
|
88
|
+
`fromIssuer` issuer and discovery URL. Each joined URL must keep the base's
|
|
89
|
+
origin and stay under the base path prefix, or the SDK throws (fail
|
|
90
|
+
closed). An endpoint must be a relative path that starts with a single
|
|
91
|
+
`/`. It may not contain `//`, a backslash, whitespace or control
|
|
92
|
+
characters, a fragment, or a percent-encoded `/`, `.` or `\` (`%2f`,
|
|
93
|
+
`%2e`, `%5c`, any case) in its path.
|
|
94
|
+
- Discovered `token_endpoint` and `jwks_uri` values carrying userinfo are now
|
|
95
|
+
rejected (`DiscoveryError`).
|
|
96
|
+
- The `clearCache()` deprecation warning now says it will be removed in a
|
|
97
|
+
future major version rather than in 6.0.0. It is still deprecated (use
|
|
98
|
+
`refreshJwks()`) and still present in 6.0.0.
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- **Discovery mode now sends `client_id` on the public-client (PKCE) token
|
|
103
|
+
exchange.** Previously `exchangeCode()` added `client_id` to the token form
|
|
104
|
+
only when a `private_key_jwt` signer was set; a public PKCE exchange sent
|
|
105
|
+
only the `X-Config-Id` header. The OP then fell back to the project's
|
|
106
|
+
default client (`token.legacy_config_id_fallback`) and stamped the id_token
|
|
107
|
+
`aud` with that client's id, so on a project with more than one public OIDC
|
|
108
|
+
client, an app using a non-default client failed verification with
|
|
109
|
+
"Unexpected JWT audience". `exchangeCode()` now always sends the configured
|
|
110
|
+
`clientId` as `client_id` in discovery mode (RFC 6749 §4.1.3), for public
|
|
111
|
+
and `private_key_jwt` clients alike; the OP resolves that specific client
|
|
112
|
+
and stamps `aud` with it. `X-Config-Id` is still sent.
|
|
113
|
+
- Single-client projects are unaffected: their `clientId` is the default
|
|
114
|
+
client, so the resolved client and `aud` are the same as before.
|
|
115
|
+
- Legacy mode (`new HawcxOAuth({ configId, baseUrl })`) has no `clientId`
|
|
116
|
+
and is unchanged: it sends no `client_id`.
|
|
117
|
+
- `ClientAssertionSigner.sign()` now reads the clock once for `iat` and `exp`.
|
|
118
|
+
Two separate reads could straddle a second boundary and make the assertion
|
|
119
|
+
one second longer than its lifetime; at `withLifetimeSeconds(120)` that
|
|
120
|
+
exceeds the OP's 120s cap and the token exchange is rejected.
|
|
121
|
+
|
|
122
|
+
## [6.0.0-rc.2] - 2026-10-10
|
|
123
|
+
|
|
124
|
+
> **Release candidate, internal only.** Published to AWS CodeArtifact
|
|
125
|
+
> (`npm-internal`), not public npm; the release workflow refuses to publish a
|
|
126
|
+
> prerelease publicly. Contains everything in 6.0.0-rc.1 plus the fix below.
|
|
127
|
+
> To install, point the `@hawcx` scope at CodeArtifact
|
|
128
|
+
> (`aws codeartifact login --tool npm --domain hawcx --repository npm-internal --namespace @hawcx`)
|
|
129
|
+
> and run `npm install @hawcx/oauth-client@6.0.0-rc.2`.
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **Discovery mode now sends `client_id` on the public-client (PKCE) token
|
|
134
|
+
exchange.** Previously `exchangeCode()` added `client_id` to the token form
|
|
135
|
+
only when a `private_key_jwt` signer was set; a public PKCE exchange sent
|
|
136
|
+
only the `X-Config-Id` header. The OP then fell back to the project's
|
|
137
|
+
default client (`token.legacy_config_id_fallback`) and stamped the id_token
|
|
138
|
+
`aud` with that client's id, so on a project with more than one public OIDC
|
|
139
|
+
client, an app using a non-default client failed verification with
|
|
140
|
+
"Unexpected JWT audience". `exchangeCode()` now always sends the configured
|
|
141
|
+
`clientId` as `client_id` in discovery mode (RFC 6749 §4.1.3), for public
|
|
142
|
+
and `private_key_jwt` clients alike; the OP resolves that specific client
|
|
143
|
+
and stamps `aud` with it. `X-Config-Id` is still sent.
|
|
144
|
+
- Single-client projects are unaffected: their `clientId` is the default
|
|
145
|
+
client, so the resolved client and `aud` are the same as before.
|
|
146
|
+
- Legacy mode (`new HawcxOAuth({ configId, baseUrl })`) has no `clientId`
|
|
147
|
+
and is unchanged: it sends no `client_id`.
|
|
148
|
+
|
|
149
|
+
## [6.0.0-rc.1] - 2026-10-07
|
|
150
|
+
|
|
151
|
+
> **Release candidate, internal only.** Published to AWS CodeArtifact
|
|
152
|
+
> (`npm-internal`), not public npm; the release workflow refuses to publish a
|
|
153
|
+
> prerelease publicly. **Major version** because of the BREAKING entries below,
|
|
154
|
+
> which change behaviour for configurations that 5.2.0 accepted. To install,
|
|
155
|
+
> point the `@hawcx` scope at CodeArtifact
|
|
156
|
+
> (`aws codeartifact login --tool npm --domain hawcx --repository npm-internal --namespace @hawcx`)
|
|
157
|
+
> and run `npm install @hawcx/oauth-client@6.0.0-rc.1`.
|
|
158
|
+
|
|
159
|
+
### Security — management API response signatures are verified by default (TOB-HSDK-11)
|
|
160
|
+
|
|
161
|
+
- **BREAKING — `JwtBearerTransport` and `StepUpClient.withPrivateKeyJwt` now
|
|
162
|
+
verify `X-Response-Signature` on every successful response, and this is on
|
|
163
|
+
by default.** This reverses the 5.2.0 note that callers "may" verify the
|
|
164
|
+
header themselves. The SDK checks the following:
|
|
165
|
+
- the JWS uses ES256, ES384 or ES512 and verifies against
|
|
166
|
+
`${issuer}/.well-known/jwks.json`;
|
|
167
|
+
- `iat` is within `clockSkewSeconds` (default 300);
|
|
168
|
+
- `body_sha256` matches the exact response bytes;
|
|
169
|
+
- the token carries no `aud`, `sub` or `nonce`.
|
|
170
|
+
|
|
171
|
+
Responses with status 400 and above are not verified. hx_auth signs every
|
|
172
|
+
jwt-mode 2xx, so production traffic is unaffected. The following will
|
|
173
|
+
**break**:
|
|
174
|
+
- A gateway, CDN or proxy that strips response headers. Every call fails
|
|
175
|
+
with `ResponseSignatureInvalidError`.
|
|
176
|
+
- Customer mocks, stubs and contract-test harnesses built against 5.2.0 that
|
|
177
|
+
return unsigned 2xx responses. Sign the responses, or disable verification
|
|
178
|
+
in the test harness.
|
|
179
|
+
- A `baseUrl` that is not the OP host, such as an internal service URL or
|
|
180
|
+
local dev with separate ports. The JWKS is fetched from `baseUrl` by
|
|
181
|
+
default, so set `issuer`.
|
|
182
|
+
- New options on both: `issuer` (defaults to `baseUrl`),
|
|
183
|
+
`verifyResponseSignature` (defaults to `true`) and `clockSkewSeconds`.
|
|
184
|
+
`verifyResponseSignature: false` is an **emergency escape hatch** that
|
|
185
|
+
restores the 5.2.0 behaviour and emits a one-time process warning.
|
|
186
|
+
`withPrivateKeyJwt` now also passes `clockSkewSeconds` through to the
|
|
187
|
+
transport.
|
|
188
|
+
- New error classes, both subclasses of `DelegationResponseError`, exported
|
|
189
|
+
with a stable `code`:
|
|
190
|
+
- `ResponseSignatureInvalidError` (`response_signature_invalid`).
|
|
191
|
+
- `ResponseSignatureUnavailableError` (`response_signature_unavailable`).
|
|
192
|
+
It means the signing keys could not be fetched, and **the request may
|
|
193
|
+
already have been applied** server-side.
|
|
194
|
+
|
|
195
|
+
### Security — structured URL validation and joining (TOB-HSDK-13)
|
|
196
|
+
|
|
197
|
+
- Every security-relevant URL is now parsed and joined with the WHATWG `URL`
|
|
198
|
+
API rather than by string concatenation. This covers `JwtBearerTransport`
|
|
199
|
+
and `DelegationTransport` (`baseUrl` + endpoint), legacy
|
|
200
|
+
`new HawcxOAuth({ baseUrl })` (`/oauth2/token` and `/keys`), and the
|
|
201
|
+
`fromIssuer` issuer and discovery URL. Each joined URL must keep the base's
|
|
202
|
+
origin and stay under the base path prefix, or the SDK throws (fail
|
|
203
|
+
closed). An endpoint must be a relative path that starts with a single
|
|
204
|
+
`/`. It may not contain `//`, a backslash, whitespace or control
|
|
205
|
+
characters, a fragment, or a percent-encoded `/`, `.` or `\` (`%2f`,
|
|
206
|
+
`%2e`, `%5c`, any case) in its path.
|
|
207
|
+
- **BREAKING — `baseUrl` (and `issuer`) values that used to be accepted now
|
|
208
|
+
throw at construction.** The affected classes are `JwtBearerTransport` and
|
|
209
|
+
`StepUpClient.withPrivateKeyJwt` (`DelegationRequestError`),
|
|
210
|
+
`DelegationTransport` and the `DelegationClient`/`StepUpClient`
|
|
211
|
+
ECIES factories (`DelegationRequestError`), legacy `HawcxOAuth`
|
|
212
|
+
(`HawcxOAuthError`), and `HawcxOAuth.fromIssuer` (`DiscoveryError`):
|
|
213
|
+
- **Plain `http:` on a non-loopback host.** Examples:
|
|
214
|
+
`http://hawcx-api:8080` (docker-compose service name),
|
|
215
|
+
`http://0.0.0.0:8080`, `http://host.docker.internal:8080`, and in-cluster
|
|
216
|
+
service URLs behind a TLS-terminating gateway. Only `localhost`,
|
|
217
|
+
`127.0.0.1` and `[::1]` may use `http:`. Use `https:`, or point the SDK
|
|
218
|
+
at a loopback address.
|
|
219
|
+
- **Userinfo, query or fragment in the base.** For example
|
|
220
|
+
`https://user:pw@api.hawcx.com`, `https://api.hawcx.com?tenant=x` or
|
|
221
|
+
`https://api.hawcx.com#x`.
|
|
222
|
+
- **BREAKING — the signed JWT `aud` string changes for non-canonical base
|
|
223
|
+
spellings.** Host case and default ports are now normalised, so
|
|
224
|
+
`baseUrl: 'https://API.Hawcx.com:443'` produces
|
|
225
|
+
`aud = https://api.hawcx.com/v1/...`, where 5.2.0 produced
|
|
226
|
+
`https://API.Hawcx.com:443/v1/...`. The new value is the one `fetch`
|
|
227
|
+
actually sends. A server that compares `aud` by exact string against a
|
|
228
|
+
configured non-canonical value will reject the new form. Canonical bases
|
|
229
|
+
(lower-case host, no default port, with or without a trailing slash or a
|
|
230
|
+
path prefix) produce byte-identical URLs and `aud`.
|
|
231
|
+
- Discovered `token_endpoint` and `jwks_uri` values carrying userinfo are now
|
|
232
|
+
rejected (`DiscoveryError`).
|
|
233
|
+
|
|
234
|
+
## [5.2.0] - 2026-06-26
|
|
235
|
+
|
|
236
|
+
### Added — Management API authentication via `private_key_jwt` (Path A)
|
|
237
|
+
|
|
238
|
+
- **`StepUpClient.withPrivateKeyJwt(...)`** — authenticate `/v1/management/*`
|
|
239
|
+
(step-up, MFA enforcement, phone-number changes) with a per-request EdDSA
|
|
240
|
+
Bearer JWT: `iss` = `sub` = `clientId`, `aud` = the full endpoint URL, ~60s
|
|
241
|
+
`exp`, random `jti`, and a `body_sha256` claim binding the JWT to the exact
|
|
242
|
+
request body bytes. Reuses the same Ed25519 OIDC `private_key_jwt` signing key
|
|
243
|
+
already registered in the admin console — one key, standards-based (RFC 7523),
|
|
244
|
+
no ECIES credential blob required. Tenant routing uses the `X-Config-Id`
|
|
245
|
+
header. Options include `timeoutSeconds` (default 15) and `jwtTtlSeconds`
|
|
246
|
+
(default 60).
|
|
247
|
+
- **`JwtBearerTransport`** — the transport backing the Path A client. Responses
|
|
248
|
+
carry an `X-Response-Signature` (ES256) which callers **may** verify against
|
|
249
|
+
the OIDC JWKS they already trust (optional, customer-side per the Path A spec).
|
|
250
|
+
|
|
251
|
+
### Changed
|
|
252
|
+
|
|
253
|
+
- The ECIES factories **`StepUpClient.fromSecretKey(...)` / `fromKeys(...)`**
|
|
254
|
+
(the proprietary `hwx_sk_v1_…` blob) are now **deprecated** — they emit a
|
|
255
|
+
one-time `DeprecationWarning` but remain fully functional and will only be
|
|
256
|
+
removed in a future major version.
|
|
257
|
+
|
|
258
|
+
### Migration (ECIES → `private_key_jwt`)
|
|
259
|
+
|
|
260
|
+
Existing ECIES integrations keep working unchanged; adopting `private_key_jwt`
|
|
261
|
+
is opt-in (spec §10.3):
|
|
262
|
+
|
|
263
|
+
1. Register your Ed25519 `private_key_jwt` public key in the Admin Console
|
|
264
|
+
(OAuth tab → **Client authentication**) — the same key used for OIDC login.
|
|
265
|
+
2. Switch the project's Management API auth to **Migrating** (accepts both
|
|
266
|
+
`ecies` and `jwt`) so existing and new callers coexist during rollout.
|
|
267
|
+
3. Replace `StepUpClient.fromSecretKey(...)` / `fromKeys(...)` with
|
|
268
|
+
`StepUpClient.withPrivateKeyJwt({ baseUrl, configId, clientId, oidcSigningKey, kid })`.
|
|
269
|
+
4. Once every caller uses `private_key_jwt`, move the project to **Signed
|
|
270
|
+
tokens** (`jwt` only). ECIES EOL date: TBA (removed no earlier than the next
|
|
271
|
+
major version).
|
|
272
|
+
|
|
273
|
+
### Hardening
|
|
274
|
+
|
|
275
|
+
- `JwtBearerTransport` now bounds every request with a timeout (`timeoutSeconds`,
|
|
276
|
+
default 15) via an `AbortController`, so a connected-but-silent server can no
|
|
277
|
+
longer hang the call or exhaust connection pools. Mirrors the ECIES
|
|
278
|
+
`DelegationTransport`.
|
|
279
|
+
- The HTTP status is now checked **before** parsing the response body, so a
|
|
280
|
+
non-JSON error body (e.g. a WAF/proxy HTML 403) surfaces its HTTP status as a
|
|
281
|
+
`DelegationRequestError` instead of being masked as a JSON parse failure.
|
|
282
|
+
|
|
283
|
+
## [5.1.0] - 2026-06-13
|
|
284
|
+
|
|
285
|
+
> The `private_key_jwt` / `ClientAssertionSigner` surface is **experimental** (`@beta`)
|
|
286
|
+
> and may change before it is marked stable.
|
|
287
|
+
|
|
288
|
+
### Cross-SDK consistency
|
|
289
|
+
|
|
290
|
+
- Added `HawcxError` as the canonical root exception (aligns with Java/Python);
|
|
291
|
+
`HawcxOAuthError` now extends it (back-compat — catch either).
|
|
292
|
+
- Added a shared **golden test vector** (`tests/fixtures/golden-assertion.json`,
|
|
293
|
+
byte-identical across the three SDKs) pinning the assertion header/claims/signature
|
|
294
|
+
for a fixed key.
|
|
295
|
+
- Added `refreshJwks()` as the canonical JWKS-cache reset (aligns with the Java
|
|
296
|
+
`refreshJwks()` / Python `refresh_jwks()` SDKs). `clearCache()` is now
|
|
297
|
+
**deprecated** (passthrough; one-time `console.warn`) and will be removed in 6.0.0.
|
|
298
|
+
|
|
299
|
+
### Production-readiness hardening
|
|
300
|
+
|
|
301
|
+
- `ClientAssertionSigner` no longer memoizes a *rejected* key import — a transient/
|
|
302
|
+
structural import failure no longer permanently poisons the signer.
|
|
303
|
+
- `jti` now sourced from `node:crypto` `randomUUID` (explicit import; was the
|
|
304
|
+
`globalThis.crypto` global).
|
|
305
|
+
- `withClientAssertion` refuses to attach a signer when the OP's discovery doc
|
|
306
|
+
advertises `token_endpoint_auth_methods_supported` without `private_key_jwt`
|
|
307
|
+
(prevents a silent downgrade to public-client).
|
|
308
|
+
- `withClientAssertion` is now **immutable** — returns a *new* configured client
|
|
309
|
+
(the backing `clientAssertionSigner` field is `readonly`) rather than mutating
|
|
310
|
+
in place. Chained usage (`(await fromIssuer(...)).withClientAssertion(...)`) is
|
|
311
|
+
unaffected; callers relying on in-place mutation of the original must use the
|
|
312
|
+
return value.
|
|
313
|
+
- `ClientAssertionSigner` gains `ed25519FromPem(pkcs8Pem, kid)` and
|
|
314
|
+
`ed25519(keyObject, kid)` factories (parity with the Java SDK).
|
|
315
|
+
- Replaced the `expectedAudience ?? ''` dead-code fallback with a non-null assertion.
|
|
316
|
+
|
|
317
|
+
### Added
|
|
318
|
+
|
|
319
|
+
- **`private_key_jwt` client authentication** (RFC 7523 / OIDC Core §9). New
|
|
320
|
+
`ClientAssertionSigner.ed25519FromJwk(...)` + `HawcxOAuth.withClientAssertion(signer)`
|
|
321
|
+
(discovery mode). When set, `exchangeCode` signs and attaches a `client_assertion`
|
|
322
|
+
(EdDSA/Ed25519 only) alongside PKCE; `aud` is the discovered `token_endpoint`.
|
|
323
|
+
Without a signer, the request is unchanged (public-client + PKCE).
|
|
324
|
+
- `exchangeCode` gains an optional 4th `expectedNonce` argument, threaded to verification.
|
|
325
|
+
|
|
326
|
+
### Changed / hardened
|
|
327
|
+
|
|
328
|
+
- **https required** on the issuer, `token_endpoint`, and `jwks_uri` (loopback http
|
|
329
|
+
still allowed for local dev/tests) — an http issuer let an on-path attacker swap
|
|
330
|
+
the discovery document.
|
|
331
|
+
- **Nonce**: verification now refuses an id_token that carries a `nonce` when none
|
|
332
|
+
was supplied to verify against (OIDC Core §3.1.3.7), instead of silently skipping it.
|
|
333
|
+
- **`exp` and `iat` required** in discovery mode — a token with no `exp` (never-expiring)
|
|
334
|
+
or no `iat` (no issuance anchor) is rejected.
|
|
335
|
+
- **Structured error fields** on the `HawcxOAuthError` hierarchy: new
|
|
336
|
+
`HawcxOAuthErrorFields` carrying optional `error` / `errorDescription`. The
|
|
337
|
+
token-endpoint error path now populates these from the OAuth `error` /
|
|
338
|
+
`error_description` body so callers can dispatch on a stable code without parsing
|
|
339
|
+
the message string (the message string composition is unchanged for back-compat).
|
|
340
|
+
- JWKS fetch timeout pinned explicitly; token-exchange error bodies that aren't JSON
|
|
341
|
+
are preserved in the error message; negative `clockToleranceSeconds` rejected.
|
|
342
|
+
|
|
343
|
+
## [5.0.0] - 2026-05-23
|
|
344
|
+
|
|
345
|
+
OIDC discovery support. The legacy `new HawcxOAuth({ configId, baseUrl })`
|
|
346
|
+
constructor is unchanged at the signature level — but verification gains a
|
|
347
|
+
default 10-second clock-tolerance window (see `clockToleranceSeconds`
|
|
348
|
+
below). Apps that depend on strict zero-skew validation should pass
|
|
349
|
+
`clockToleranceSeconds: 0`.
|
|
350
|
+
|
|
351
|
+
### Added
|
|
352
|
+
|
|
353
|
+
#### OIDC discovery construction path
|
|
354
|
+
|
|
355
|
+
- `HawcxOAuth.fromIssuer({ issuer, configId, clientId })` — static async
|
|
356
|
+
factory that fetches `<issuer>/.well-known/openid-configuration` once at
|
|
357
|
+
startup (5s default timeout) and wires a verifier that enforces signature
|
|
358
|
+
+ `iss` + `aud` + `exp` + `nbf` on every subsequent `verifyToken` call.
|
|
359
|
+
The legacy path verifies the signature only.
|
|
360
|
+
|
|
361
|
+
**`configId` vs `clientId`.** Hawcx separates the tenant routing key from
|
|
362
|
+
the audience claim, and the SDK forwards each to the right place:
|
|
363
|
+
- `configId` — sent as `X-Config-Id` on the token-exchange POST (opaque
|
|
364
|
+
tenant routing key)
|
|
365
|
+
- `clientId` — the value the tenant has configured (in the Hawcx admin
|
|
366
|
+
console) as the `aud` claim on issued id_tokens. The verifier matches
|
|
367
|
+
the token's `aud` against this exact string.
|
|
368
|
+
|
|
369
|
+
Passing the same value for both fails verification with
|
|
370
|
+
`Unexpected JWT audience` unless the tenant happens to configure them
|
|
371
|
+
identically.
|
|
372
|
+
|
|
373
|
+
- `HawcxOAuth.prototype.exchangeCode(code, codeVerifier, redirectUri?)` —
|
|
374
|
+
new optional third argument. If your authorization request registered a
|
|
375
|
+
`redirect_uri`, RFC 6749 §4.1.3 requires the token request to carry the
|
|
376
|
+
same value. Omit for flows that didn't include it.
|
|
377
|
+
|
|
378
|
+
- `HawcxOAuth.prototype.verifyToken(token, { nonce })` — new options object
|
|
379
|
+
with optional `nonce` field for callers who bind a nonce to the
|
|
380
|
+
authorization request. Has no effect in legacy mode.
|
|
381
|
+
|
|
382
|
+
- `HawcxOAuth.prototype.discoveryMetadata` — the resolved OIDC discovery
|
|
383
|
+
document. `null` on legacy clients; useful for diagnostics ("which
|
|
384
|
+
token endpoint did we resolve to?", "what signing algorithms?").
|
|
385
|
+
|
|
386
|
+
- `clockToleranceSeconds` option on both `HawcxOAuthConfig` (legacy) and
|
|
387
|
+
`HawcxOAuthIssuerConfig` (discovery) — tolerated clock skew in seconds
|
|
388
|
+
when verifying `exp` and `nbf`. Spec.md §3.3 mandates this knob with a
|
|
389
|
+
recommended default of 10 seconds, which the SDK now applies. Without
|
|
390
|
+
it, jose's default of 0 rejected tokens minted under normal NTP drift
|
|
391
|
+
between issuer and verifier — the root cause of the
|
|
392
|
+
`exchangeCodeTolerant` workaround in `hawcx_admin_console` pre-5.0.
|
|
393
|
+
Pass `clockToleranceSeconds: 0` to opt back into strict exact-time
|
|
394
|
+
validation; raise above 10 if drift on your hosts is wider than that.
|
|
395
|
+
|
|
396
|
+
- **Algorithm allowlist (spec.md §3.3) — discovery mode.** `fromIssuer`
|
|
397
|
+
now intersects the issuer's advertised
|
|
398
|
+
`id_token_signing_alg_values_supported` with a closed SDK allowlist
|
|
399
|
+
(`{RS256, ES256, ES384, ES512, EdDSA}`). If no advertised alg is in
|
|
400
|
+
the allowlist, `DiscoveryError` is thrown at construction time. The
|
|
401
|
+
intersection is then passed to `jose.jwtVerify`'s `algorithms` option
|
|
402
|
+
on every `verifyToken` call, so verify-time enforcement matches what
|
|
403
|
+
was resolved at construction — forecloses key-confusion /
|
|
404
|
+
alg-substitution where the JWKS happens to serve a key type matching
|
|
405
|
+
whatever the JWT header claims. Mirrors the Java SDK
|
|
406
|
+
(`JwtVerifier.DEFAULT_ALGORITHMS`). Legacy mode behavior is unchanged
|
|
407
|
+
(no closed allowlist, no `algorithms:` constraint — same as 4.x).
|
|
408
|
+
|
|
409
|
+
- `DiscoveryError` — new error class for discovery-resolution failures
|
|
410
|
+
(DNS / TLS / network failure, non-2xx response, malformed JSON, missing
|
|
411
|
+
required fields). Underlying cause is preserved as `err.cause`.
|
|
412
|
+
|
|
413
|
+
- New exported types: `HawcxOAuthIssuerConfig`, `DiscoveryMetadata`,
|
|
414
|
+
`VerifyTokenOptions`.
|
|
415
|
+
|
|
416
|
+
### Changed
|
|
417
|
+
|
|
418
|
+
- `TokenVerificationError.message` now distinguishes audience / issuer
|
|
419
|
+
mismatches from generic signature failures by parsing jose's
|
|
420
|
+
`ERR_JWT_CLAIM_VALIDATION_FAILED` code. Code that pattern-matched on
|
|
421
|
+
the legacy "Invalid signature" message still sees it for signature
|
|
422
|
+
failures; new "Unexpected JWT audience" / "Unexpected JWT issuer"
|
|
423
|
+
messages are now used when those specific claims fail.
|
|
424
|
+
|
|
425
|
+
- `exchangeCode` now sets `grant_type=authorization_code` on the form body.
|
|
426
|
+
4.x callers won't notice — the OAuth server already inferred the grant
|
|
427
|
+
type from the presence of `code`. Listed here for completeness.
|
|
428
|
+
|
|
429
|
+
### Notes for upgraders
|
|
430
|
+
|
|
431
|
+
If you only construct via `new HawcxOAuth({ configId })`, nothing changes —
|
|
432
|
+
the legacy path is signature-only verification, same as 4.x. If you want
|
|
433
|
+
proper `aud`/`iss` enforcement, switch to `await HawcxOAuth.fromIssuer(...)`
|
|
434
|
+
and pass both `configId` and `clientId` from the admin console.
|
|
435
|
+
|
|
436
|
+
## [0.2.0] - 2024-11-20
|
|
437
|
+
|
|
438
|
+
### Breaking Changes
|
|
439
|
+
- **BREAKING**: `apiKey` parameter is now required in `exchangeCodeForClaims()` and `exchangeCodeForTokenAndClaims()`
|
|
440
|
+
- **BREAKING**: At least one of `publicKey` or `jwksUrl` must be provided for JWT verification
|
|
441
|
+
|
|
442
|
+
### Added
|
|
443
|
+
- Validation to ensure `apiKey` is provided and non-empty
|
|
444
|
+
- Validation to ensure at least one of `publicKey` or `jwksUrl` is provided
|
|
445
|
+
- Clear error messages for missing required parameters
|
|
446
|
+
- Priority logic: `jwksUrl` takes precedence over `publicKey` when both are provided
|
|
447
|
+
|
|
448
|
+
### Changed
|
|
449
|
+
- Updated all documentation and examples to use `jwksUrl` as the primary recommended method
|
|
450
|
+
- Updated demo application to include `apiKey` parameter
|
|
451
|
+
- Improved error messages for parameter validation
|
|
452
|
+
|
|
453
|
+
### Fixed
|
|
454
|
+
- Ensures API key is always sent with OAuth token exchange requests
|
|
455
|
+
- Prevents authentication failures due to missing API key
|
|
456
|
+
|
|
457
|
+
## [0.1.0] - 2024-01-XX
|
|
458
|
+
|
|
459
|
+
### Added
|
|
460
|
+
- Initial release of Node.js/TypeScript OAuth client SDK
|
|
461
|
+
- OAuth authorization code exchange with PKCE support
|
|
462
|
+
- JWT verification with RS256, ES256/384/512, and EdDSA algorithms
|
|
463
|
+
- Comprehensive error handling with custom exception classes
|
|
464
|
+
- Hawcx delegation client for MFA setup and management
|
|
465
|
+
- ECIES (X25519 + AES-GCM) encryption for secure backend-to-backend communication
|
|
466
|
+
- Ed25519 and RSA-PSS signing support
|
|
467
|
+
- Full TypeScript type definitions
|
|
468
|
+
- Comprehensive documentation and examples
|
|
469
|
+
- Feature parity with Python SDK
|
|
470
|
+
|
|
471
|
+
### Features
|
|
472
|
+
- 🔐 Secure JWT verification with configurable validation
|
|
473
|
+
- 🆕 Native PKCE (RFC 7636) support
|
|
474
|
+
- 🚀 Simple, async/await API
|
|
475
|
+
- 🎯 High-level Hawcx client with automatic encryption/signing
|
|
476
|
+
- 🛡️ Comprehensive error handling
|
|
477
|
+
- 📝 Full TypeScript support
|
|
478
|
+
- 🔧 Framework-agnostic (works with Express, Fastify, etc.)
|
|
479
|
+
|
package/README.md
CHANGED
|
@@ -450,22 +450,65 @@ try {
|
|
|
450
450
|
|
|
451
451
|
For step-up authentication flows (e.g., changing MFA method requires re-authentication).
|
|
452
452
|
|
|
453
|
-
### `StepUpClient`
|
|
453
|
+
### `StepUpClient` (recommended: `withPrivateKeyJwt`)
|
|
454
|
+
|
|
455
|
+
`StepUpClient.withPrivateKeyJwt` is the recommended construction path. It reuses
|
|
456
|
+
the same Ed25519 `private_key_jwt` signing key already registered in the Hawcx admin
|
|
457
|
+
console for OIDC — one standards-based key, no separate credential blob required.
|
|
454
458
|
|
|
455
459
|
```typescript
|
|
456
460
|
import { StepUpClient } from '@hawcx/oauth-client';
|
|
457
461
|
|
|
458
|
-
const
|
|
462
|
+
const privateJwk = JSON.parse(process.env.HAWCX_PRIVATE_JWK!); // OKP/Ed25519, with kid
|
|
463
|
+
|
|
464
|
+
const stepUp = StepUpClient.withPrivateKeyJwt({
|
|
459
465
|
baseUrl: 'https://api.hawcx.com',
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
+
configId: process.env.HAWCX_CONFIG_ID!, // X-Config-Id tenant routing
|
|
467
|
+
clientId: process.env.HAWCX_CLIENT_ID!, // iss/sub in per-request JWT
|
|
468
|
+
oidcSigningKey: privateJwk, // same key as ClientAssertionSigner
|
|
469
|
+
kid: privateJwk.kid,
|
|
470
|
+
relyingParty: 'your-app.com', // Optional
|
|
471
|
+
apiKey: 'optional-api-key', // Optional
|
|
472
|
+
apiPrefix: '/v1', // Optional (default: '/v1')
|
|
466
473
|
});
|
|
467
474
|
```
|
|
468
475
|
|
|
476
|
+
The signing key must be Ed25519 (`kty: 'OKP', crv: 'Ed25519'`). It accepts a JWK
|
|
477
|
+
object, a PKCS#8 PEM string, or a pre-imported jose `KeyLike`.
|
|
478
|
+
|
|
479
|
+
Each request is signed with a short-lived per-request EdDSA JWT whose `aud` is the
|
|
480
|
+
full request URL and whose `body_sha256` claim covers the exact bytes sent.
|
|
481
|
+
|
|
482
|
+
Every successful response is authenticated too. The SDK verifies the
|
|
483
|
+
`X-Response-Signature` JWS (ES256/ES384/ES512) against
|
|
484
|
+
`${issuer}/.well-known/jwks.json`. It also checks that the JWS `iat` is within
|
|
485
|
+
`clockSkewSeconds` (default 300) and that its `body_sha256` matches the exact
|
|
486
|
+
response bytes. `issuer` defaults to `baseUrl`, because the management API and
|
|
487
|
+
the OP share a host in every Hawcx environment. Set `issuer` explicitly if they
|
|
488
|
+
differ, for example in local development.
|
|
489
|
+
|
|
490
|
+
> **Scope:** by default the JWKS comes from the **same origin as the API**.
|
|
491
|
+
> Verification therefore protects against tampering *between* that origin and
|
|
492
|
+
> you: caches, proxies and gateways, or a compromised downstream service. It
|
|
493
|
+
> does **not** protect against a compromised origin. If you need that, pin
|
|
494
|
+
> `issuer` to a separately trusted host.
|
|
495
|
+
|
|
496
|
+
Failures throw one of two subclasses of `DelegationResponseError`, each with a
|
|
497
|
+
stable `code`:
|
|
498
|
+
|
|
499
|
+
- `ResponseSignatureInvalidError` (`code: 'response_signature_invalid'`): the
|
|
500
|
+
header is missing or empty, or the signature does not verify. Treat the
|
|
501
|
+
response as untrusted.
|
|
502
|
+
- `ResponseSignatureUnavailableError` (`code: 'response_signature_unavailable'`):
|
|
503
|
+
the signing keys could not be obtained. The JWKS fetch failed, timed out or
|
|
504
|
+
returned something unusable, or a newly rotated `kid` arrived while refetching
|
|
505
|
+
was cooling down. **The server has already processed the request**, so a
|
|
506
|
+
non-idempotent write such as `consumeReceipt` may have been applied. Reconcile
|
|
507
|
+
state rather than retrying blindly.
|
|
508
|
+
|
|
509
|
+
`verifyResponseSignature: false` turns verification off. It is an emergency
|
|
510
|
+
escape hatch only, and it logs a one-time process warning.
|
|
511
|
+
|
|
469
512
|
### Methods
|
|
470
513
|
|
|
471
514
|
#### `stepUp.startToken(options): Promise<StepUpStartTokenResponse>`
|
|
@@ -512,6 +555,23 @@ interface StepUpConsumeResponse {
|
|
|
512
555
|
}
|
|
513
556
|
```
|
|
514
557
|
|
|
558
|
+
### Legacy (deprecated): `fromSecretKey`
|
|
559
|
+
|
|
560
|
+
`StepUpClient.fromSecretKey` and `StepUpClient.fromKeys` are deprecated since 5.2.0
|
|
561
|
+
and will be removed in a future major version. They use a proprietary ECIES credential
|
|
562
|
+
format. Migrate to `withPrivateKeyJwt`.
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
// DEPRECATED — migrate to withPrivateKeyJwt above
|
|
566
|
+
import { StepUpClient } from '@hawcx/oauth-client';
|
|
567
|
+
|
|
568
|
+
const stepUp = StepUpClient.fromSecretKey({
|
|
569
|
+
baseUrl: 'https://api.hawcx.com',
|
|
570
|
+
secretKey: process.env.HAWCX_SECRET_KEY!, // hwx_sk_v1_… blob
|
|
571
|
+
relyingParty: 'your-app.com',
|
|
572
|
+
});
|
|
573
|
+
```
|
|
574
|
+
|
|
515
575
|
---
|
|
516
576
|
|
|
517
577
|
## Examples
|
|
@@ -595,9 +655,14 @@ async function revokeAllDevices(userId: string) {
|
|
|
595
655
|
```typescript
|
|
596
656
|
import { StepUpClient, DelegationClient, MfaMethod } from '@hawcx/oauth-client';
|
|
597
657
|
|
|
598
|
-
const
|
|
658
|
+
const privateJwk = JSON.parse(process.env.HAWCX_PRIVATE_JWK!);
|
|
659
|
+
|
|
660
|
+
const stepUp = StepUpClient.withPrivateKeyJwt({
|
|
599
661
|
baseUrl: process.env.HAWCX_API_URL!,
|
|
600
|
-
|
|
662
|
+
configId: process.env.HAWCX_CONFIG_ID!,
|
|
663
|
+
clientId: process.env.HAWCX_CLIENT_ID!,
|
|
664
|
+
oidcSigningKey: privateJwk,
|
|
665
|
+
kid: privateJwk.kid,
|
|
601
666
|
relyingParty: 'myapp.com',
|
|
602
667
|
});
|
|
603
668
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-assertion.d.ts","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAmC,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAKjE,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,2DACwB,CAAC;AAK3D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,iEAAiE;IACjE,OAAO,CAAC,UAAU,CAAC,CAAuB;IAE1C,OAAO;IAUP;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,GAAG,MAAM,GAAG,qBAAqB;IA0BtE;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,qBAAqB;IAkB3E;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,qBAAqB;IAazE;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB;IAK3D,OAAO,CAAC,SAAS;IAYjB;;;;;;OAMG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client-assertion.d.ts","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAmC,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAKjE,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,2DACwB,CAAC;AAK3D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,iEAAiE;IACjE,OAAO,CAAC,UAAU,CAAC,CAAuB;IAE1C,OAAO;IAUP;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,GAAG,MAAM,GAAG,qBAAqB;IA0BtE;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,qBAAqB;IAkB3E;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,qBAAqB;IAazE;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB;IAK3D,OAAO,CAAC,SAAS;IAYjB;;;;;;OAMG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAgBhE"}
|
package/dist/client-assertion.js
CHANGED
|
@@ -119,13 +119,17 @@ class ClientAssertionSigner {
|
|
|
119
119
|
*/
|
|
120
120
|
async sign(clientId, audience) {
|
|
121
121
|
const key = await this.importKey();
|
|
122
|
+
// One clock read for both claims: separate reads can straddle a second
|
|
123
|
+
// boundary and make exp - iat one second longer than the lifetime, which at
|
|
124
|
+
// the 120s maximum exceeds the OP's cap.
|
|
125
|
+
const now = Math.floor(Date.now() / 1000);
|
|
122
126
|
return new jose_1.SignJWT({})
|
|
123
127
|
.setProtectedHeader({ alg: 'EdDSA', typ: 'JWT', kid: this.kid })
|
|
124
128
|
.setIssuer(clientId)
|
|
125
129
|
.setSubject(clientId)
|
|
126
130
|
.setAudience(audience)
|
|
127
|
-
.setIssuedAt()
|
|
128
|
-
.setExpirationTime(
|
|
131
|
+
.setIssuedAt(now)
|
|
132
|
+
.setExpirationTime(now + this.lifetimeSeconds)
|
|
129
133
|
.setJti((0, node_crypto_1.randomUUID)())
|
|
130
134
|
.sign(key);
|
|
131
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-assertion.js","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"client-assertion.js","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"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"}
|