@tdacorp/identity-client 0.1.0 → 0.2.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/README.md CHANGED
@@ -160,6 +160,23 @@ const tokens = await exchangeAuthorizationCode({
160
160
  })
161
161
  ```
162
162
 
163
+ If your relying party is registered on the identity platform for
164
+ `client_secret_post` rather than the default `client_secret_basic`, pass
165
+ `clientAuthMethod` so credentials are sent the way the token endpoint
166
+ actually expects them:
167
+
168
+ ```ts
169
+ const tokens = await exchangeAuthorizationCode({
170
+ issuer: 'https://identity.tdacorp.in',
171
+ clientId: process.env.IDENTITY_CLIENT_ID!,
172
+ clientSecret: process.env.IDENTITY_CLIENT_SECRET!,
173
+ clientAuthMethod: 'client_secret_post',
174
+ code,
175
+ redirectUri,
176
+ codeVerifier,
177
+ })
178
+ ```
179
+
163
180
  Refresh (RFC 6749 §6), returning a classified outcome instead of throwing —
164
181
  so a transient infrastructure failure is never mistaken for a rejected
165
182
  refresh token:
@@ -269,12 +286,6 @@ instead.
269
286
 
270
287
  ## Limitations in v0.1
271
288
 
272
- - **Only `client_secret_basic` client authentication is supported** for the
273
- authorization-code exchange (`exchangeAuthorizationCode` sends an HTTP
274
- Basic `Authorization` header when a `clientSecret` is given). A relying
275
- party configured on TDACorp Identity for `client_secret_post` cannot use
276
- `exchangeAuthorizationCode` as-is today — the token endpoint will reject
277
- the request.
278
289
  - **No built-in fallback for an `indeterminate` `permits()` result.** That is
279
290
  `@tdacorp/identity-authz`'s concern, not this package's, but worth knowing
280
291
  up front since most integrations hit both together — see that package's
@@ -135,13 +135,16 @@ function toTokenSet(body) {
135
135
  scope: body.scope
136
136
  };
137
137
  }
138
- async function postTokenRequest(tokenEndpoint, clientId, clientSecret, params) {
138
+ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
139
139
  const body = new URLSearchParams(params);
140
140
  const headers = {
141
141
  "Content-Type": "application/x-www-form-urlencoded",
142
142
  Accept: "application/json"
143
143
  };
144
- if (clientSecret) {
144
+ if (clientSecret && clientAuthMethod === "client_secret_post") {
145
+ body.set("client_id", clientId);
146
+ body.set("client_secret", clientSecret);
147
+ } else if (clientSecret) {
145
148
  headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
146
149
  } else {
147
150
  body.set("client_id", clientId);
@@ -153,12 +156,18 @@ async function readTokenResponseBody(response) {
153
156
  }
154
157
  async function exchangeAuthorizationCode(options) {
155
158
  const discovery = await fetchDiscovery(options.issuer);
156
- const response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
157
- grant_type: "authorization_code",
158
- code: options.code,
159
- redirect_uri: options.redirectUri,
160
- code_verifier: options.codeVerifier
161
- });
159
+ const response = await postTokenRequest(
160
+ discovery.token_endpoint,
161
+ options.clientId,
162
+ options.clientSecret,
163
+ options.clientAuthMethod ?? "client_secret_basic",
164
+ {
165
+ grant_type: "authorization_code",
166
+ code: options.code,
167
+ redirect_uri: options.redirectUri,
168
+ code_verifier: options.codeVerifier
169
+ }
170
+ );
162
171
  const body = await readTokenResponseBody(response);
163
172
  if (!response.ok || !body || body.error || typeof body.access_token !== "string") {
164
173
  throw new TokenRequestError({ status: response.status, error: body?.error, errorDescription: body?.error_description });
@@ -167,10 +176,16 @@ async function exchangeAuthorizationCode(options) {
167
176
  }
168
177
  async function clientCredentialsGrant(options) {
169
178
  const discovery = await fetchDiscovery(options.issuer);
170
- const response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
171
- grant_type: "client_credentials",
172
- ...options.scope ? { scope: options.scope } : {}
173
- });
179
+ const response = await postTokenRequest(
180
+ discovery.token_endpoint,
181
+ options.clientId,
182
+ options.clientSecret,
183
+ options.clientAuthMethod ?? "client_secret_basic",
184
+ {
185
+ grant_type: "client_credentials",
186
+ ...options.scope ? { scope: options.scope } : {}
187
+ }
188
+ );
174
189
  const body = await readTokenResponseBody(response);
175
190
  if (!response.ok || !body || body.error || typeof body.access_token !== "string") {
176
191
  throw new TokenRequestError({ status: response.status, error: body?.error, errorDescription: body?.error_description });
@@ -185,10 +200,16 @@ async function refreshTokens(options) {
185
200
  let response;
186
201
  try {
187
202
  const discovery = await fetchDiscovery(options.issuer);
188
- response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
189
- grant_type: "refresh_token",
190
- refresh_token: options.refreshToken
191
- });
203
+ response = await postTokenRequest(
204
+ discovery.token_endpoint,
205
+ options.clientId,
206
+ options.clientSecret,
207
+ options.clientAuthMethod ?? "client_secret_basic",
208
+ {
209
+ grant_type: "refresh_token",
210
+ refresh_token: options.refreshToken
211
+ }
212
+ );
192
213
  } catch (error) {
193
214
  return { outcome: "transient", error };
194
215
  }
package/dist/index.cjs CHANGED
@@ -172,13 +172,16 @@ function toTokenSet(body) {
172
172
  scope: body.scope
173
173
  };
174
174
  }
175
- async function postTokenRequest(tokenEndpoint, clientId, clientSecret, params) {
175
+ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
176
176
  const body = new URLSearchParams(params);
177
177
  const headers = {
178
178
  "Content-Type": "application/x-www-form-urlencoded",
179
179
  Accept: "application/json"
180
180
  };
181
- if (clientSecret) {
181
+ if (clientSecret && clientAuthMethod === "client_secret_post") {
182
+ body.set("client_id", clientId);
183
+ body.set("client_secret", clientSecret);
184
+ } else if (clientSecret) {
182
185
  headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
183
186
  } else {
184
187
  body.set("client_id", clientId);
@@ -190,12 +193,18 @@ async function readTokenResponseBody(response) {
190
193
  }
191
194
  async function exchangeAuthorizationCode(options) {
192
195
  const discovery = await fetchDiscovery(options.issuer);
193
- const response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
194
- grant_type: "authorization_code",
195
- code: options.code,
196
- redirect_uri: options.redirectUri,
197
- code_verifier: options.codeVerifier
198
- });
196
+ const response = await postTokenRequest(
197
+ discovery.token_endpoint,
198
+ options.clientId,
199
+ options.clientSecret,
200
+ options.clientAuthMethod ?? "client_secret_basic",
201
+ {
202
+ grant_type: "authorization_code",
203
+ code: options.code,
204
+ redirect_uri: options.redirectUri,
205
+ code_verifier: options.codeVerifier
206
+ }
207
+ );
199
208
  const body = await readTokenResponseBody(response);
200
209
  if (!response.ok || !body || body.error || typeof body.access_token !== "string") {
201
210
  throw new TokenRequestError({ status: response.status, error: body?.error, errorDescription: body?.error_description });
@@ -204,10 +213,16 @@ async function exchangeAuthorizationCode(options) {
204
213
  }
205
214
  async function clientCredentialsGrant(options) {
206
215
  const discovery = await fetchDiscovery(options.issuer);
207
- const response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
208
- grant_type: "client_credentials",
209
- ...options.scope ? { scope: options.scope } : {}
210
- });
216
+ const response = await postTokenRequest(
217
+ discovery.token_endpoint,
218
+ options.clientId,
219
+ options.clientSecret,
220
+ options.clientAuthMethod ?? "client_secret_basic",
221
+ {
222
+ grant_type: "client_credentials",
223
+ ...options.scope ? { scope: options.scope } : {}
224
+ }
225
+ );
211
226
  const body = await readTokenResponseBody(response);
212
227
  if (!response.ok || !body || body.error || typeof body.access_token !== "string") {
213
228
  throw new TokenRequestError({ status: response.status, error: body?.error, errorDescription: body?.error_description });
@@ -222,10 +237,16 @@ async function refreshTokens(options) {
222
237
  let response;
223
238
  try {
224
239
  const discovery = await fetchDiscovery(options.issuer);
225
- response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
226
- grant_type: "refresh_token",
227
- refresh_token: options.refreshToken
228
- });
240
+ response = await postTokenRequest(
241
+ discovery.token_endpoint,
242
+ options.clientId,
243
+ options.clientSecret,
244
+ options.clientAuthMethod ?? "client_secret_basic",
245
+ {
246
+ grant_type: "refresh_token",
247
+ refresh_token: options.refreshToken
248
+ }
249
+ );
229
250
  } catch (error) {
230
251
  return { outcome: "transient", error };
231
252
  }
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRemoteJWKSet } from 'jose';
2
- export { A as AuthorizationCodeExchangeOptions, C as CLOCK_SKEW_TOLERANCE_SECONDS, a as ClientCredentialsGrantOptions, I as IdTokenClaims, R as RefreshTokensOptions, T as TokenRefreshOutcome, b as TokenRequestError, c as TokenSet, d as TokenVerificationError, e as TokenVerificationErrorCode, V as VerificationResult, f as VerifiedAccessToken, g as VerifyTokenOptions, h as clientCredentialsGrant, i as exchangeAuthorizationCode, r as refreshTokens, v as verifyAccessToken, j as verifyIdToken } from './verify-BiGhwaIz.cjs';
2
+ export { A as AuthorizationCodeExchangeOptions, C as CLOCK_SKEW_TOLERANCE_SECONDS, a as ClientCredentialsGrantOptions, I as IdTokenClaims, R as RefreshTokensOptions, T as TokenEndpointAuthMethod, b as TokenRefreshOutcome, c as TokenRequestError, d as TokenSet, e as TokenVerificationError, f as TokenVerificationErrorCode, V as VerificationResult, g as VerifiedAccessToken, h as VerifyTokenOptions, i as clientCredentialsGrant, j as exchangeAuthorizationCode, r as refreshTokens, v as verifyAccessToken, k as verifyIdToken } from './verify-DTUDjR4v.cjs';
3
3
  import '@tdacorp/identity-authz';
4
4
 
5
5
  /**
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRemoteJWKSet } from 'jose';
2
- export { A as AuthorizationCodeExchangeOptions, C as CLOCK_SKEW_TOLERANCE_SECONDS, a as ClientCredentialsGrantOptions, I as IdTokenClaims, R as RefreshTokensOptions, T as TokenRefreshOutcome, b as TokenRequestError, c as TokenSet, d as TokenVerificationError, e as TokenVerificationErrorCode, V as VerificationResult, f as VerifiedAccessToken, g as VerifyTokenOptions, h as clientCredentialsGrant, i as exchangeAuthorizationCode, r as refreshTokens, v as verifyAccessToken, j as verifyIdToken } from './verify-BiGhwaIz.js';
2
+ export { A as AuthorizationCodeExchangeOptions, C as CLOCK_SKEW_TOLERANCE_SECONDS, a as ClientCredentialsGrantOptions, I as IdTokenClaims, R as RefreshTokensOptions, T as TokenEndpointAuthMethod, b as TokenRefreshOutcome, c as TokenRequestError, d as TokenSet, e as TokenVerificationError, f as TokenVerificationErrorCode, V as VerificationResult, g as VerifiedAccessToken, h as VerifyTokenOptions, i as clientCredentialsGrant, j as exchangeAuthorizationCode, r as refreshTokens, v as verifyAccessToken, k as verifyIdToken } from './verify-DTUDjR4v.js';
3
3
  import '@tdacorp/identity-authz';
4
4
 
5
5
  /**
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  refreshTokens,
12
12
  verifyAccessToken,
13
13
  verifyIdToken
14
- } from "./chunk-VJSMXIZB.js";
14
+ } from "./chunk-6WGVTO7C.js";
15
15
  export {
16
16
  CLOCK_SKEW_TOLERANCE_SECONDS,
17
17
  TokenRequestError,
package/dist/next.cjs CHANGED
@@ -163,13 +163,16 @@ function toTokenSet(body) {
163
163
  scope: body.scope
164
164
  };
165
165
  }
166
- async function postTokenRequest(tokenEndpoint, clientId, clientSecret, params) {
166
+ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
167
167
  const body = new URLSearchParams(params);
168
168
  const headers = {
169
169
  "Content-Type": "application/x-www-form-urlencoded",
170
170
  Accept: "application/json"
171
171
  };
172
- if (clientSecret) {
172
+ if (clientSecret && clientAuthMethod === "client_secret_post") {
173
+ body.set("client_id", clientId);
174
+ body.set("client_secret", clientSecret);
175
+ } else if (clientSecret) {
173
176
  headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
174
177
  } else {
175
178
  body.set("client_id", clientId);
@@ -181,12 +184,18 @@ async function readTokenResponseBody(response) {
181
184
  }
182
185
  async function exchangeAuthorizationCode(options) {
183
186
  const discovery = await fetchDiscovery(options.issuer);
184
- const response = await postTokenRequest(discovery.token_endpoint, options.clientId, options.clientSecret, {
185
- grant_type: "authorization_code",
186
- code: options.code,
187
- redirect_uri: options.redirectUri,
188
- code_verifier: options.codeVerifier
189
- });
187
+ const response = await postTokenRequest(
188
+ discovery.token_endpoint,
189
+ options.clientId,
190
+ options.clientSecret,
191
+ options.clientAuthMethod ?? "client_secret_basic",
192
+ {
193
+ grant_type: "authorization_code",
194
+ code: options.code,
195
+ redirect_uri: options.redirectUri,
196
+ code_verifier: options.codeVerifier
197
+ }
198
+ );
190
199
  const body = await readTokenResponseBody(response);
191
200
  if (!response.ok || !body || body.error || typeof body.access_token !== "string") {
192
201
  throw new TokenRequestError({ status: response.status, error: body?.error, errorDescription: body?.error_description });
package/dist/next.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextResponse, NextRequest } from 'next/server';
2
- import { c as TokenSet, I as IdTokenClaims } from './verify-BiGhwaIz.cjs';
2
+ import { d as TokenSet, I as IdTokenClaims } from './verify-DTUDjR4v.cjs';
3
3
  import { SealSecret } from './sealed.cjs';
4
4
  import '@tdacorp/identity-authz';
5
5
  import 'jose';
package/dist/next.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextResponse, NextRequest } from 'next/server';
2
- import { c as TokenSet, I as IdTokenClaims } from './verify-BiGhwaIz.js';
2
+ import { d as TokenSet, I as IdTokenClaims } from './verify-DTUDjR4v.js';
3
3
  import { SealSecret } from './sealed.js';
4
4
  import '@tdacorp/identity-authz';
5
5
  import 'jose';
package/dist/next.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  generateCodeVerifier,
6
6
  generateState,
7
7
  verifyIdToken
8
- } from "./chunk-VJSMXIZB.js";
8
+ } from "./chunk-6WGVTO7C.js";
9
9
  import {
10
10
  seal,
11
11
  unseal
@@ -31,6 +31,10 @@ declare class TokenRequestError extends Error {
31
31
  errorDescription?: string;
32
32
  });
33
33
  }
34
+ /** The token endpoint client-authentication methods this package supports --
35
+ * see RFC 6749 §2.3.1 and OIDC Discovery 1.0's
36
+ * `token_endpoint_auth_methods_supported`. */
37
+ type TokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post';
34
38
  /** Options for `exchangeAuthorizationCode`. */
35
39
  interface AuthorizationCodeExchangeOptions {
36
40
  /** The identity server's issuer URL, used to look up `token_endpoint`. */
@@ -46,6 +50,16 @@ interface AuthorizationCodeExchangeOptions {
46
50
  /** The PKCE verifier generated (and kept) alongside the code challenge
47
51
  * sent on the authorization request; see `generateCodeVerifier`. */
48
52
  codeVerifier: string;
53
+ /** How to send `clientSecret` to the token endpoint. Defaults to
54
+ * `'client_secret_basic'`, which is this package's original and only
55
+ * behavior -- omitting this field changes nothing for an existing caller.
56
+ * Set it to `'client_secret_post'` if the relying party is registered on
57
+ * the identity platform for that method instead: sending Basic auth to a
58
+ * `client_secret_post`-only client gets `invalid_client` back, since the
59
+ * token endpoint never receives credentials in the form it expects. An
60
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
61
+ * says which methods it actually accepts. */
62
+ clientAuthMethod?: TokenEndpointAuthMethod;
49
63
  }
50
64
  /** RFC 6749 §4.1.3 / RFC 7636 §4.5: exchanges an authorization code for a
51
65
  * token set. Throws `TokenRequestError` on any non-success response. */
@@ -60,6 +74,16 @@ interface ClientCredentialsGrantOptions {
60
74
  clientSecret: string;
61
75
  /** Space-separated scopes to request for the resulting token. */
62
76
  scope?: string;
77
+ /** How to send `clientSecret` to the token endpoint. Defaults to
78
+ * `'client_secret_basic'`, which is this package's original and only
79
+ * behavior -- omitting this field changes nothing for an existing caller.
80
+ * Set it to `'client_secret_post'` if the relying party is registered on
81
+ * the identity platform for that method instead: sending Basic auth to a
82
+ * `client_secret_post`-only client gets `invalid_client` back, since the
83
+ * token endpoint never receives credentials in the form it expects. An
84
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
85
+ * says which methods it actually accepts. */
86
+ clientAuthMethod?: TokenEndpointAuthMethod;
63
87
  }
64
88
  /** RFC 6749 §4.4: mints a token with no end user, for service-to-service
65
89
  * calls. Always confidential -- `clientSecret` is required, not optional,
@@ -75,6 +99,16 @@ interface RefreshTokensOptions {
75
99
  clientSecret?: string;
76
100
  /** The refresh token to redeem. */
77
101
  refreshToken: string;
102
+ /** How to send `clientSecret` to the token endpoint. Defaults to
103
+ * `'client_secret_basic'`, which is this package's original and only
104
+ * behavior -- omitting this field changes nothing for an existing caller.
105
+ * Set it to `'client_secret_post'` if the relying party is registered on
106
+ * the identity platform for that method instead: sending Basic auth to a
107
+ * `client_secret_post`-only client gets `invalid_client` back, since the
108
+ * token endpoint never receives credentials in the form it expects. An
109
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
110
+ * says which methods it actually accepts. */
111
+ clientAuthMethod?: TokenEndpointAuthMethod;
78
112
  }
79
113
  type TokenRefreshOutcome = {
80
114
  outcome: 'success';
@@ -303,4 +337,4 @@ declare function verifyIdToken(idToken: string, options: VerifyTokenOptions): Pr
303
337
  * contract as `verifyIdToken`. */
304
338
  declare function verifyAccessToken(accessToken: string, options: VerifyTokenOptions): Promise<VerificationResult<VerifiedAccessToken>>;
305
339
 
306
- export { type AuthorizationCodeExchangeOptions as A, CLOCK_SKEW_TOLERANCE_SECONDS as C, type IdTokenClaims as I, type RefreshTokensOptions as R, type TokenRefreshOutcome as T, type VerificationResult as V, type ClientCredentialsGrantOptions as a, TokenRequestError as b, type TokenSet as c, type TokenVerificationError as d, type TokenVerificationErrorCode as e, type VerifiedAccessToken as f, type VerifyTokenOptions as g, clientCredentialsGrant as h, exchangeAuthorizationCode as i, verifyIdToken as j, refreshTokens as r, verifyAccessToken as v };
340
+ export { type AuthorizationCodeExchangeOptions as A, CLOCK_SKEW_TOLERANCE_SECONDS as C, type IdTokenClaims as I, type RefreshTokensOptions as R, type TokenEndpointAuthMethod as T, type VerificationResult as V, type ClientCredentialsGrantOptions as a, type TokenRefreshOutcome as b, TokenRequestError as c, type TokenSet as d, type TokenVerificationError as e, type TokenVerificationErrorCode as f, type VerifiedAccessToken as g, type VerifyTokenOptions as h, clientCredentialsGrant as i, exchangeAuthorizationCode as j, verifyIdToken as k, refreshTokens as r, verifyAccessToken as v };
@@ -31,6 +31,10 @@ declare class TokenRequestError extends Error {
31
31
  errorDescription?: string;
32
32
  });
33
33
  }
34
+ /** The token endpoint client-authentication methods this package supports --
35
+ * see RFC 6749 §2.3.1 and OIDC Discovery 1.0's
36
+ * `token_endpoint_auth_methods_supported`. */
37
+ type TokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post';
34
38
  /** Options for `exchangeAuthorizationCode`. */
35
39
  interface AuthorizationCodeExchangeOptions {
36
40
  /** The identity server's issuer URL, used to look up `token_endpoint`. */
@@ -46,6 +50,16 @@ interface AuthorizationCodeExchangeOptions {
46
50
  /** The PKCE verifier generated (and kept) alongside the code challenge
47
51
  * sent on the authorization request; see `generateCodeVerifier`. */
48
52
  codeVerifier: string;
53
+ /** How to send `clientSecret` to the token endpoint. Defaults to
54
+ * `'client_secret_basic'`, which is this package's original and only
55
+ * behavior -- omitting this field changes nothing for an existing caller.
56
+ * Set it to `'client_secret_post'` if the relying party is registered on
57
+ * the identity platform for that method instead: sending Basic auth to a
58
+ * `client_secret_post`-only client gets `invalid_client` back, since the
59
+ * token endpoint never receives credentials in the form it expects. An
60
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
61
+ * says which methods it actually accepts. */
62
+ clientAuthMethod?: TokenEndpointAuthMethod;
49
63
  }
50
64
  /** RFC 6749 §4.1.3 / RFC 7636 §4.5: exchanges an authorization code for a
51
65
  * token set. Throws `TokenRequestError` on any non-success response. */
@@ -60,6 +74,16 @@ interface ClientCredentialsGrantOptions {
60
74
  clientSecret: string;
61
75
  /** Space-separated scopes to request for the resulting token. */
62
76
  scope?: string;
77
+ /** How to send `clientSecret` to the token endpoint. Defaults to
78
+ * `'client_secret_basic'`, which is this package's original and only
79
+ * behavior -- omitting this field changes nothing for an existing caller.
80
+ * Set it to `'client_secret_post'` if the relying party is registered on
81
+ * the identity platform for that method instead: sending Basic auth to a
82
+ * `client_secret_post`-only client gets `invalid_client` back, since the
83
+ * token endpoint never receives credentials in the form it expects. An
84
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
85
+ * says which methods it actually accepts. */
86
+ clientAuthMethod?: TokenEndpointAuthMethod;
63
87
  }
64
88
  /** RFC 6749 §4.4: mints a token with no end user, for service-to-service
65
89
  * calls. Always confidential -- `clientSecret` is required, not optional,
@@ -75,6 +99,16 @@ interface RefreshTokensOptions {
75
99
  clientSecret?: string;
76
100
  /** The refresh token to redeem. */
77
101
  refreshToken: string;
102
+ /** How to send `clientSecret` to the token endpoint. Defaults to
103
+ * `'client_secret_basic'`, which is this package's original and only
104
+ * behavior -- omitting this field changes nothing for an existing caller.
105
+ * Set it to `'client_secret_post'` if the relying party is registered on
106
+ * the identity platform for that method instead: sending Basic auth to a
107
+ * `client_secret_post`-only client gets `invalid_client` back, since the
108
+ * token endpoint never receives credentials in the form it expects. An
109
+ * issuer's OIDC discovery document's `token_endpoint_auth_methods_supported`
110
+ * says which methods it actually accepts. */
111
+ clientAuthMethod?: TokenEndpointAuthMethod;
78
112
  }
79
113
  type TokenRefreshOutcome = {
80
114
  outcome: 'success';
@@ -303,4 +337,4 @@ declare function verifyIdToken(idToken: string, options: VerifyTokenOptions): Pr
303
337
  * contract as `verifyIdToken`. */
304
338
  declare function verifyAccessToken(accessToken: string, options: VerifyTokenOptions): Promise<VerificationResult<VerifiedAccessToken>>;
305
339
 
306
- export { type AuthorizationCodeExchangeOptions as A, CLOCK_SKEW_TOLERANCE_SECONDS as C, type IdTokenClaims as I, type RefreshTokensOptions as R, type TokenRefreshOutcome as T, type VerificationResult as V, type ClientCredentialsGrantOptions as a, TokenRequestError as b, type TokenSet as c, type TokenVerificationError as d, type TokenVerificationErrorCode as e, type VerifiedAccessToken as f, type VerifyTokenOptions as g, clientCredentialsGrant as h, exchangeAuthorizationCode as i, verifyIdToken as j, refreshTokens as r, verifyAccessToken as v };
340
+ export { type AuthorizationCodeExchangeOptions as A, CLOCK_SKEW_TOLERANCE_SECONDS as C, type IdTokenClaims as I, type RefreshTokensOptions as R, type TokenEndpointAuthMethod as T, type VerificationResult as V, type ClientCredentialsGrantOptions as a, type TokenRefreshOutcome as b, TokenRequestError as c, type TokenSet as d, type TokenVerificationError as e, type TokenVerificationErrorCode as f, type VerifiedAccessToken as g, type VerifyTokenOptions as h, clientCredentialsGrant as i, exchangeAuthorizationCode as j, verifyIdToken as k, refreshTokens as r, verifyAccessToken as v };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdacorp/identity-client",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "OIDC relying-party client for TDACorp Identity: discovery, PKCE, token exchange, token verification and Next.js route helpers.",
5
5
  "license": "MIT",
6
6
  "bugs": {
@@ -50,17 +50,12 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "scripts": {
54
- "build": "tsup",
55
- "typecheck": "tsc --noEmit",
56
- "test": "vitest run"
57
- },
58
53
  "files": [
59
54
  "dist"
60
55
  ],
61
56
  "dependencies": {
62
- "@tdacorp/identity-authz": "workspace:*",
63
- "jose": "^6.2.9"
57
+ "jose": "^6.2.9",
58
+ "@tdacorp/identity-authz": "^0.2.0"
64
59
  },
65
60
  "peerDependencies": {
66
61
  "next": ">=14"
@@ -71,10 +66,15 @@
71
66
  }
72
67
  },
73
68
  "devDependencies": {
74
- "@tdacorp/typescript-config": "workspace:*",
75
69
  "next": "^16.3.2",
76
70
  "tsup": "^8.5.1",
77
71
  "typescript": "^5.7.3",
78
- "vitest": "^4.1.11"
72
+ "vitest": "^4.1.11",
73
+ "@tdacorp/typescript-config": "0.0.0"
74
+ },
75
+ "scripts": {
76
+ "build": "tsup",
77
+ "typecheck": "tsc --noEmit",
78
+ "test": "vitest run"
79
79
  }
80
- }
80
+ }