@tdacorp/identity-client 0.2.1 → 0.2.3
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/dist/{chunk-S5WGUOJA.js → chunk-MB66JUMG.js} +24 -2
- package/dist/index.cjs +24 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/next.cjs +17 -1
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +1 -1
- package/dist/{verify-C1Ga6JbS.d.cts → verify-ggSzUrdC.d.cts} +7 -1
- package/dist/{verify-C1Ga6JbS.d.ts → verify-ggSzUrdC.d.ts} +7 -1
- package/package.json +2 -2
|
@@ -129,6 +129,16 @@ var TokenRequestError = class extends Error {
|
|
|
129
129
|
this.errorDescription = details.errorDescription;
|
|
130
130
|
}
|
|
131
131
|
};
|
|
132
|
+
async function fetchDiscoveryForTokenRequest(issuer) {
|
|
133
|
+
try {
|
|
134
|
+
return await fetchDiscovery(issuer);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
throw new TokenRequestError({
|
|
137
|
+
error: "discovery_failed",
|
|
138
|
+
errorDescription: error instanceof Error ? error.message : "Failed to fetch the issuer's discovery document"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
132
142
|
function toTokenSet(body) {
|
|
133
143
|
return {
|
|
134
144
|
accessToken: body.access_token,
|
|
@@ -159,7 +169,7 @@ async function readTokenResponseBody(response) {
|
|
|
159
169
|
return await response.json().catch(() => null);
|
|
160
170
|
}
|
|
161
171
|
async function exchangeAuthorizationCode(options) {
|
|
162
|
-
const discovery = await
|
|
172
|
+
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
163
173
|
const response = await postTokenRequest(
|
|
164
174
|
discovery.token_endpoint,
|
|
165
175
|
options.clientId,
|
|
@@ -179,7 +189,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
179
189
|
return toTokenSet(body);
|
|
180
190
|
}
|
|
181
191
|
async function clientCredentialsGrant(options) {
|
|
182
|
-
const discovery = await
|
|
192
|
+
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
183
193
|
const response = await postTokenRequest(
|
|
184
194
|
discovery.token_endpoint,
|
|
185
195
|
options.clientId,
|
|
@@ -306,6 +316,12 @@ async function verifyIdToken(idToken, options) {
|
|
|
306
316
|
const result = await verifyAgainstIssuer(idToken, options);
|
|
307
317
|
if ("errors" in result) return { success: false, errors: result.errors };
|
|
308
318
|
const { payload } = result;
|
|
319
|
+
if ("token_use" in payload) {
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
errors: [{ code: "wrong-token-type", message: "Token has a token_use claim; an id_token never carries one. This is an access token, not an id_token." }]
|
|
323
|
+
};
|
|
324
|
+
}
|
|
309
325
|
if (typeof payload.sub !== "string") {
|
|
310
326
|
return { success: false, errors: [{ code: "malformed-claims", message: "id_token has no sub claim" }] };
|
|
311
327
|
}
|
|
@@ -315,6 +331,12 @@ async function verifyAccessToken(accessToken, options) {
|
|
|
315
331
|
const result = await verifyAgainstIssuer(accessToken, options);
|
|
316
332
|
if ("errors" in result) return { success: false, errors: result.errors };
|
|
317
333
|
const { payload } = result;
|
|
334
|
+
if (payload.token_use !== "oauth_access") {
|
|
335
|
+
return {
|
|
336
|
+
success: false,
|
|
337
|
+
errors: [{ code: "wrong-token-type", message: 'Token is missing token_use: "oauth_access". This is not an access token (likely an id_token).' }]
|
|
338
|
+
};
|
|
339
|
+
}
|
|
318
340
|
const claims = payload;
|
|
319
341
|
const roles = "roles" in claims ? claims.roles : void 0;
|
|
320
342
|
if (typeof payload.sub === "string") {
|
package/dist/index.cjs
CHANGED
|
@@ -166,6 +166,16 @@ var TokenRequestError = class extends Error {
|
|
|
166
166
|
this.errorDescription = details.errorDescription;
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
|
+
async function fetchDiscoveryForTokenRequest(issuer) {
|
|
170
|
+
try {
|
|
171
|
+
return await fetchDiscovery(issuer);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
throw new TokenRequestError({
|
|
174
|
+
error: "discovery_failed",
|
|
175
|
+
errorDescription: error instanceof Error ? error.message : "Failed to fetch the issuer's discovery document"
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
169
179
|
function toTokenSet(body) {
|
|
170
180
|
return {
|
|
171
181
|
accessToken: body.access_token,
|
|
@@ -196,7 +206,7 @@ async function readTokenResponseBody(response) {
|
|
|
196
206
|
return await response.json().catch(() => null);
|
|
197
207
|
}
|
|
198
208
|
async function exchangeAuthorizationCode(options) {
|
|
199
|
-
const discovery = await
|
|
209
|
+
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
200
210
|
const response = await postTokenRequest(
|
|
201
211
|
discovery.token_endpoint,
|
|
202
212
|
options.clientId,
|
|
@@ -216,7 +226,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
216
226
|
return toTokenSet(body);
|
|
217
227
|
}
|
|
218
228
|
async function clientCredentialsGrant(options) {
|
|
219
|
-
const discovery = await
|
|
229
|
+
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
220
230
|
const response = await postTokenRequest(
|
|
221
231
|
discovery.token_endpoint,
|
|
222
232
|
options.clientId,
|
|
@@ -343,6 +353,12 @@ async function verifyIdToken(idToken, options) {
|
|
|
343
353
|
const result = await verifyAgainstIssuer(idToken, options);
|
|
344
354
|
if ("errors" in result) return { success: false, errors: result.errors };
|
|
345
355
|
const { payload } = result;
|
|
356
|
+
if ("token_use" in payload) {
|
|
357
|
+
return {
|
|
358
|
+
success: false,
|
|
359
|
+
errors: [{ code: "wrong-token-type", message: "Token has a token_use claim; an id_token never carries one. This is an access token, not an id_token." }]
|
|
360
|
+
};
|
|
361
|
+
}
|
|
346
362
|
if (typeof payload.sub !== "string") {
|
|
347
363
|
return { success: false, errors: [{ code: "malformed-claims", message: "id_token has no sub claim" }] };
|
|
348
364
|
}
|
|
@@ -352,6 +368,12 @@ async function verifyAccessToken(accessToken, options) {
|
|
|
352
368
|
const result = await verifyAgainstIssuer(accessToken, options);
|
|
353
369
|
if ("errors" in result) return { success: false, errors: result.errors };
|
|
354
370
|
const { payload } = result;
|
|
371
|
+
if (payload.token_use !== "oauth_access") {
|
|
372
|
+
return {
|
|
373
|
+
success: false,
|
|
374
|
+
errors: [{ code: "wrong-token-type", message: 'Token is missing token_use: "oauth_access". This is not an access token (likely an id_token).' }]
|
|
375
|
+
};
|
|
376
|
+
}
|
|
355
377
|
const claims = payload;
|
|
356
378
|
const roles = "roles" in claims ? claims.roles : void 0;
|
|
357
379
|
if (typeof payload.sub === "string") {
|
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 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-
|
|
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-ggSzUrdC.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 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-
|
|
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-ggSzUrdC.js';
|
|
3
3
|
import '@tdacorp/identity-authz';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/index.js
CHANGED
package/dist/next.cjs
CHANGED
|
@@ -157,6 +157,16 @@ var TokenRequestError = class extends Error {
|
|
|
157
157
|
this.errorDescription = details.errorDescription;
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
|
+
async function fetchDiscoveryForTokenRequest(issuer) {
|
|
161
|
+
try {
|
|
162
|
+
return await fetchDiscovery(issuer);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
throw new TokenRequestError({
|
|
165
|
+
error: "discovery_failed",
|
|
166
|
+
errorDescription: error instanceof Error ? error.message : "Failed to fetch the issuer's discovery document"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
160
170
|
function toTokenSet(body) {
|
|
161
171
|
return {
|
|
162
172
|
accessToken: body.access_token,
|
|
@@ -187,7 +197,7 @@ async function readTokenResponseBody(response) {
|
|
|
187
197
|
return await response.json().catch(() => null);
|
|
188
198
|
}
|
|
189
199
|
async function exchangeAuthorizationCode(options) {
|
|
190
|
-
const discovery = await
|
|
200
|
+
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
191
201
|
const response = await postTokenRequest(
|
|
192
202
|
discovery.token_endpoint,
|
|
193
203
|
options.clientId,
|
|
@@ -280,6 +290,12 @@ async function verifyIdToken(idToken, options) {
|
|
|
280
290
|
const result = await verifyAgainstIssuer(idToken, options);
|
|
281
291
|
if ("errors" in result) return { success: false, errors: result.errors };
|
|
282
292
|
const { payload } = result;
|
|
293
|
+
if ("token_use" in payload) {
|
|
294
|
+
return {
|
|
295
|
+
success: false,
|
|
296
|
+
errors: [{ code: "wrong-token-type", message: "Token has a token_use claim; an id_token never carries one. This is an access token, not an id_token." }]
|
|
297
|
+
};
|
|
298
|
+
}
|
|
283
299
|
if (typeof payload.sub !== "string") {
|
|
284
300
|
return { success: false, errors: [{ code: "malformed-claims", message: "id_token has no sub claim" }] };
|
|
285
301
|
}
|
package/dist/next.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextResponse, NextRequest } from 'next/server';
|
|
2
|
-
import { d as TokenSet, I as IdTokenClaims } from './verify-
|
|
2
|
+
import { d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.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 { d as TokenSet, I as IdTokenClaims } from './verify-
|
|
2
|
+
import { d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.js';
|
|
3
3
|
import { SealSecret } from './sealed.js';
|
|
4
4
|
import '@tdacorp/identity-authz';
|
|
5
5
|
import 'jose';
|
package/dist/next.js
CHANGED
|
@@ -246,8 +246,14 @@ declare const CLOCK_SKEW_TOLERANCE_SECONDS = 60;
|
|
|
246
246
|
* - `'malformed-token'`: the token is not a well-formed JWT at all.
|
|
247
247
|
* - `'jwks-unavailable'`: the issuer's discovery document or JWKS could not
|
|
248
248
|
* be fetched -- infrastructure, not a verdict on the token.
|
|
249
|
+
* - `'wrong-token-type'`: the token verified (right issuer, right audience,
|
|
250
|
+
* right signature) but is the OTHER kind of token this server mints for a
|
|
251
|
+
* login -- an id_token presented to `verifyAccessToken`, or an access
|
|
252
|
+
* token presented to `verifyIdToken`. The two share `iss`/`sub`/`aud`/`azp`
|
|
253
|
+
* and are signed by the same key, so nothing else here would catch this;
|
|
254
|
+
* see `token_use` on `IdentityTokenPayload`.
|
|
249
255
|
*/
|
|
250
|
-
type TokenVerificationErrorCode = 'expired' | 'invalid-signature' | 'invalid-issuer' | 'invalid-audience' | 'unauthorized-party' | 'malformed-claims' | 'malformed-token' | 'jwks-unavailable';
|
|
256
|
+
type TokenVerificationErrorCode = 'expired' | 'invalid-signature' | 'invalid-issuer' | 'invalid-audience' | 'unauthorized-party' | 'malformed-claims' | 'malformed-token' | 'jwks-unavailable' | 'wrong-token-type';
|
|
251
257
|
/** One verification failure: a stable `code` to branch on, plus a
|
|
252
258
|
* human-readable `message` for logs. `verifyIdToken`/`verifyAccessToken`
|
|
253
259
|
* return a list of these rather than throwing -- see `VerificationResult`. */
|
|
@@ -246,8 +246,14 @@ declare const CLOCK_SKEW_TOLERANCE_SECONDS = 60;
|
|
|
246
246
|
* - `'malformed-token'`: the token is not a well-formed JWT at all.
|
|
247
247
|
* - `'jwks-unavailable'`: the issuer's discovery document or JWKS could not
|
|
248
248
|
* be fetched -- infrastructure, not a verdict on the token.
|
|
249
|
+
* - `'wrong-token-type'`: the token verified (right issuer, right audience,
|
|
250
|
+
* right signature) but is the OTHER kind of token this server mints for a
|
|
251
|
+
* login -- an id_token presented to `verifyAccessToken`, or an access
|
|
252
|
+
* token presented to `verifyIdToken`. The two share `iss`/`sub`/`aud`/`azp`
|
|
253
|
+
* and are signed by the same key, so nothing else here would catch this;
|
|
254
|
+
* see `token_use` on `IdentityTokenPayload`.
|
|
249
255
|
*/
|
|
250
|
-
type TokenVerificationErrorCode = 'expired' | 'invalid-signature' | 'invalid-issuer' | 'invalid-audience' | 'unauthorized-party' | 'malformed-claims' | 'malformed-token' | 'jwks-unavailable';
|
|
256
|
+
type TokenVerificationErrorCode = 'expired' | 'invalid-signature' | 'invalid-issuer' | 'invalid-audience' | 'unauthorized-party' | 'malformed-claims' | 'malformed-token' | 'jwks-unavailable' | 'wrong-token-type';
|
|
251
257
|
/** One verification failure: a stable `code` to branch on, plus a
|
|
252
258
|
* human-readable `message` for logs. `verifyIdToken`/`verifyAccessToken`
|
|
253
259
|
* return a list of these rather than throwing -- see `VerificationResult`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tdacorp/identity-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
],
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"jose": "^6.2.9",
|
|
58
|
-
"@tdacorp/identity-authz": "^0.2.
|
|
58
|
+
"@tdacorp/identity-authz": "^0.2.1"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"next": ">=14"
|