oauth4webapi 2.11.0 → 2.12.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 +4 -2
- package/build/index.d.ts +62 -57
- package/build/index.js +17 -14
- package/package.json +16 -17
package/README.md
CHANGED
|
@@ -21,10 +21,12 @@ The following features are currently in scope and implemented in this software:
|
|
|
21
21
|
|
|
22
22
|
[<img width="96" height="50" align="right" src="https://user-images.githubusercontent.com/241506/166977513-7cd710a9-7f60-4944-aebe-a658e9f36375.png" alt="OpenID Certification">](#certification)
|
|
23
23
|
|
|
24
|
-
[Filip Skokan](https://github.com/panva) has certified that [this software](https://github.com/panva/oauth4webapi) conforms to the Basic, FAPI 1.0
|
|
24
|
+
[Filip Skokan](https://github.com/panva) has certified that [this software](https://github.com/panva/oauth4webapi) conforms to the Basic, FAPI 1.0, and FAPI 2.0 Relying Party Conformance Profiles of the OpenID Connect™ protocol.
|
|
25
25
|
|
|
26
26
|
## [💗 Help the project](https://github.com/sponsors/panva)
|
|
27
27
|
|
|
28
|
+
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).
|
|
29
|
+
|
|
28
30
|
## Dependencies: 0
|
|
29
31
|
|
|
30
32
|
`oauth4webapi` has no dependencies and it exports tree-shakeable ESM.
|
|
@@ -44,7 +46,7 @@ import * as oauth from 'oauth4webapi'
|
|
|
44
46
|
**`example`** Deno import
|
|
45
47
|
|
|
46
48
|
```js
|
|
47
|
-
import * as oauth from 'https://deno.land/x/oauth4webapi@v2.
|
|
49
|
+
import * as oauth from 'https://deno.land/x/oauth4webapi@v2.12.0/mod.ts'
|
|
48
50
|
```
|
|
49
51
|
|
|
50
52
|
- Authorization Code Flow (OAuth 2.0) - [source](examples/oauth.ts)
|
package/build/index.d.ts
CHANGED
|
@@ -148,7 +148,51 @@ export interface JWK {
|
|
|
148
148
|
readonly y?: string;
|
|
149
149
|
readonly [parameter: string]: JsonValue | undefined;
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Use to adjust the assumed current time. Positive and negative finite values representing seconds
|
|
153
|
+
* are allowed. Default is `0` (Date.now() + 0 seconds is used).
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
*
|
|
157
|
+
* When the local clock is mistakenly 1 hour in the past
|
|
158
|
+
*
|
|
159
|
+
* ```ts
|
|
160
|
+
* const client: oauth.Client = {
|
|
161
|
+
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
162
|
+
* // ... other metadata
|
|
163
|
+
* [oauth.clockSkew]: +(60 * 60),
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
*
|
|
169
|
+
* When the local clock is mistakenly 1 hour in the future
|
|
170
|
+
*
|
|
171
|
+
* ```ts
|
|
172
|
+
* const client: oauth.Client = {
|
|
173
|
+
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
174
|
+
* // ... other metadata
|
|
175
|
+
* [oauth.clockSkew]: -(60 * 60),
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
151
179
|
export declare const clockSkew: unique symbol;
|
|
180
|
+
/**
|
|
181
|
+
* Use to set allowed clock tolerance when checking DateTime JWT Claims. Only positive finite values
|
|
182
|
+
* representing seconds are allowed. Default is `30` (30 seconds).
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
*
|
|
186
|
+
* Tolerate 30 seconds clock skew when validating JWT claims like exp or nbf.
|
|
187
|
+
*
|
|
188
|
+
* ```ts
|
|
189
|
+
* const client: oauth.Client = {
|
|
190
|
+
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
191
|
+
* // ... other metadata
|
|
192
|
+
* [oauth.clockTolerance]: 30,
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
152
196
|
export declare const clockTolerance: unique symbol;
|
|
153
197
|
/**
|
|
154
198
|
* When configured on an interface that extends {@link HttpRequestOptions}, this applies to `options`
|
|
@@ -235,9 +279,6 @@ export declare const clockTolerance: unique symbol;
|
|
|
235
279
|
*/
|
|
236
280
|
export declare const customFetch: unique symbol;
|
|
237
281
|
/**
|
|
238
|
-
* This is an experimental feature, it is not subject to semantic versioning rules. Non-backward
|
|
239
|
-
* compatible changes or removal may occur in any future release.
|
|
240
|
-
*
|
|
241
282
|
* DANGER ZONE - This option has security implications that must be understood, assessed for
|
|
242
283
|
* applicability, and accepted before use. It is critical that the JSON Web Key Set cache only be
|
|
243
284
|
* writable by your own code.
|
|
@@ -281,7 +322,7 @@ export declare const customFetch: unique symbol;
|
|
|
281
322
|
*
|
|
282
323
|
* // Use JSON Web Key Set cache
|
|
283
324
|
* const accessTokenClaims = await validateJwtAccessToken(as, request, expectedAudience, {
|
|
284
|
-
* [oauth.
|
|
325
|
+
* [oauth.jwksCache]: jwksCache,
|
|
285
326
|
* })
|
|
286
327
|
*
|
|
287
328
|
* if (uat !== jwksCache.uat) {
|
|
@@ -290,7 +331,7 @@ export declare const customFetch: unique symbol;
|
|
|
290
331
|
* }
|
|
291
332
|
* ```
|
|
292
333
|
*/
|
|
293
|
-
export declare const
|
|
334
|
+
export declare const jwksCache: unique symbol;
|
|
294
335
|
/**
|
|
295
336
|
* When combined with {@link customFetch} (to use a Fetch API implementation that supports client
|
|
296
337
|
* certificates) this can be used to target FAPI 2.0 profiles that utilize Mutual-TLS for either
|
|
@@ -734,49 +775,11 @@ export interface Client {
|
|
|
734
775
|
*/
|
|
735
776
|
default_max_age?: number;
|
|
736
777
|
/**
|
|
737
|
-
*
|
|
738
|
-
* representing seconds are allowed. Default is `0` (Date.now() + 0 seconds is used).
|
|
739
|
-
*
|
|
740
|
-
* @example
|
|
741
|
-
*
|
|
742
|
-
* When the client's local clock is mistakenly 1 hour in the past
|
|
743
|
-
*
|
|
744
|
-
* ```ts
|
|
745
|
-
* const client: oauth.Client = {
|
|
746
|
-
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
747
|
-
* // ... other metadata
|
|
748
|
-
* [oauth.clockSkew]: +(60 * 60),
|
|
749
|
-
* }
|
|
750
|
-
* ```
|
|
751
|
-
*
|
|
752
|
-
* @example
|
|
753
|
-
*
|
|
754
|
-
* When the client's local clock is mistakenly 1 hour in the future
|
|
755
|
-
*
|
|
756
|
-
* ```ts
|
|
757
|
-
* const client: oauth.Client = {
|
|
758
|
-
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
759
|
-
* // ... other metadata
|
|
760
|
-
* [oauth.clockSkew]: -(60 * 60),
|
|
761
|
-
* }
|
|
762
|
-
* ```
|
|
778
|
+
* See {@link clockSkew}.
|
|
763
779
|
*/
|
|
764
780
|
[clockSkew]?: number;
|
|
765
781
|
/**
|
|
766
|
-
*
|
|
767
|
-
* finite values representing seconds are allowed. Default is `30` (30 seconds).
|
|
768
|
-
*
|
|
769
|
-
* @example
|
|
770
|
-
*
|
|
771
|
-
* Tolerate 30 seconds clock skew when validating JWT claims like exp or nbf.
|
|
772
|
-
*
|
|
773
|
-
* ```ts
|
|
774
|
-
* const client: oauth.Client = {
|
|
775
|
-
* client_id: 'abc4ba37-4ab8-49b5-99d4-9441ba35d428',
|
|
776
|
-
* // ... other metadata
|
|
777
|
-
* [oauth.clockTolerance]: 30,
|
|
778
|
-
* }
|
|
779
|
-
* ```
|
|
782
|
+
* See {@link clockTolerance}.
|
|
780
783
|
*/
|
|
781
784
|
[clockTolerance]?: number;
|
|
782
785
|
[metadata: string]: JsonValue | undefined;
|
|
@@ -797,9 +800,9 @@ export declare class OperationProcessingError extends Error {
|
|
|
797
800
|
}
|
|
798
801
|
export interface JWKSCacheOptions {
|
|
799
802
|
/**
|
|
800
|
-
* See {@link
|
|
803
|
+
* See {@link jwksCache}.
|
|
801
804
|
*/
|
|
802
|
-
[
|
|
805
|
+
[jwksCache]?: JWKSCacheInput;
|
|
803
806
|
}
|
|
804
807
|
export interface HttpRequestOptions {
|
|
805
808
|
/**
|
|
@@ -822,7 +825,7 @@ export interface HttpRequestOptions {
|
|
|
822
825
|
/**
|
|
823
826
|
* See {@link customFetch}.
|
|
824
827
|
*/
|
|
825
|
-
[customFetch]?:
|
|
828
|
+
[customFetch]?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
826
829
|
}
|
|
827
830
|
export interface DiscoveryRequestOptions extends HttpRequestOptions {
|
|
828
831
|
/**
|
|
@@ -1054,11 +1057,7 @@ export declare function parseWwwAuthenticateChallenges(response: Response): WWWA
|
|
|
1054
1057
|
export declare function processPushedAuthorizationResponse(as: AuthorizationServer, client: Client, response: Response): Promise<PushedAuthorizationResponse | OAuth2Error>;
|
|
1055
1058
|
export interface ProtectedResourceRequestOptions extends Omit<HttpRequestOptions, 'headers'>, DPoPRequestOptions {
|
|
1056
1059
|
/**
|
|
1057
|
-
*
|
|
1058
|
-
* representing seconds are allowed. Default is `0` (Date.now() + 0 seconds is used).
|
|
1059
|
-
*
|
|
1060
|
-
* This option only affects the request if the {@link ProtectedResourceRequestOptions.DPoP DPoP}
|
|
1061
|
-
* option is also used.
|
|
1060
|
+
* See {@link clockSkew}.
|
|
1062
1061
|
*/
|
|
1063
1062
|
[clockSkew]?: number;
|
|
1064
1063
|
}
|
|
@@ -1711,11 +1710,11 @@ export interface ValidateJWTAccessTokenOptions extends HttpRequestOptions, JWKSC
|
|
|
1711
1710
|
*/
|
|
1712
1711
|
requireDPoP?: boolean;
|
|
1713
1712
|
/**
|
|
1714
|
-
*
|
|
1713
|
+
* See {@link clockSkew}.
|
|
1715
1714
|
*/
|
|
1716
1715
|
[clockSkew]?: number;
|
|
1717
1716
|
/**
|
|
1718
|
-
*
|
|
1717
|
+
* See {@link clockTolerance}.
|
|
1719
1718
|
*/
|
|
1720
1719
|
[clockTolerance]?: number;
|
|
1721
1720
|
}
|
|
@@ -1794,11 +1793,17 @@ export type IntrospectionConfirmationClaims = ConfirmationClaims;
|
|
|
1794
1793
|
*
|
|
1795
1794
|
* @deprecated Use {@link validateDetachedSignatureResponse}.
|
|
1796
1795
|
*/
|
|
1797
|
-
export declare const experimental_validateDetachedSignatureResponse: typeof
|
|
1796
|
+
export declare const experimental_validateDetachedSignatureResponse: (as: AuthorizationServer, client: Client, parameters: URLSearchParams | URL, expectedNonce: string, expectedState?: string | typeof expectNoState | undefined, maxAge?: number | typeof skipAuthTimeCheck | undefined, options?: ValidateDetachedSignatureResponseOptions | undefined) => Promise<URLSearchParams | OAuth2Error>;
|
|
1798
1797
|
/**
|
|
1799
1798
|
* @ignore
|
|
1800
1799
|
*
|
|
1801
1800
|
* @deprecated Use {@link validateJwtAccessToken}.
|
|
1802
1801
|
*/
|
|
1803
|
-
export declare const experimental_validateJwtAccessToken:
|
|
1802
|
+
export declare const experimental_validateJwtAccessToken: (as: AuthorizationServer, request: Request, expectedAudience: string, options?: ValidateJWTAccessTokenOptions | undefined) => Promise<JWTAccessTokenClaims>;
|
|
1803
|
+
/**
|
|
1804
|
+
* @ignore
|
|
1805
|
+
*
|
|
1806
|
+
* @deprecated Use {@link jwksCache}.
|
|
1807
|
+
*/
|
|
1808
|
+
export declare const experimental_jwksCache: symbol;
|
|
1804
1809
|
export {};
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
let USER_AGENT;
|
|
2
2
|
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
|
|
3
3
|
const NAME = 'oauth4webapi';
|
|
4
|
-
const VERSION = 'v2.
|
|
4
|
+
const VERSION = 'v2.12.0';
|
|
5
5
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
6
6
|
}
|
|
7
7
|
function looseInstanceOf(input, expected) {
|
|
@@ -19,7 +19,7 @@ function looseInstanceOf(input, expected) {
|
|
|
19
19
|
export const clockSkew = Symbol();
|
|
20
20
|
export const clockTolerance = Symbol();
|
|
21
21
|
export const customFetch = Symbol();
|
|
22
|
-
export const
|
|
22
|
+
export const jwksCache = Symbol();
|
|
23
23
|
export const useMtlsAlias = Symbol();
|
|
24
24
|
const encoder = new TextEncoder();
|
|
25
25
|
const decoder = new TextDecoder();
|
|
@@ -767,8 +767,8 @@ function clearJwksCache(as, cache) {
|
|
|
767
767
|
async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
768
768
|
const { alg, kid } = header;
|
|
769
769
|
checkSupportedJwsAlg(alg);
|
|
770
|
-
if (!jwksMap?.has(as) && isFreshJwksCache(options?.[
|
|
771
|
-
setJwksCache(as, options?.[
|
|
770
|
+
if (!jwksMap?.has(as) && isFreshJwksCache(options?.[jwksCache])) {
|
|
771
|
+
setJwksCache(as, options?.[jwksCache].jwks, options?.[jwksCache].uat);
|
|
772
772
|
}
|
|
773
773
|
let jwks;
|
|
774
774
|
let age;
|
|
@@ -776,14 +776,14 @@ async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
|
776
776
|
;
|
|
777
777
|
({ jwks, age } = jwksMap.get(as));
|
|
778
778
|
if (age >= 300) {
|
|
779
|
-
clearJwksCache(as, options?.[
|
|
779
|
+
clearJwksCache(as, options?.[jwksCache]);
|
|
780
780
|
return getPublicSigKeyFromIssuerJwksUri(as, options, header);
|
|
781
781
|
}
|
|
782
782
|
}
|
|
783
783
|
else {
|
|
784
784
|
jwks = await jwksRequest(as, options).then(processJwksResponse);
|
|
785
785
|
age = 0;
|
|
786
|
-
setJwksCache(as, jwks, epochTime(), options?.[
|
|
786
|
+
setJwksCache(as, jwks, epochTime(), options?.[jwksCache]);
|
|
787
787
|
}
|
|
788
788
|
let kty;
|
|
789
789
|
switch (alg.slice(0, 2)) {
|
|
@@ -828,7 +828,7 @@ async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
|
828
828
|
const { 0: jwk, length } = candidates;
|
|
829
829
|
if (!length) {
|
|
830
830
|
if (age >= 60) {
|
|
831
|
-
clearJwksCache(as, options?.[
|
|
831
|
+
clearJwksCache(as, options?.[jwksCache]);
|
|
832
832
|
return getPublicSigKeyFromIssuerJwksUri(as, options, header);
|
|
833
833
|
}
|
|
834
834
|
throw new OPE('error when selecting a JWT verification key, no applicable keys found');
|
|
@@ -994,8 +994,9 @@ async function processGenericAccessTokenResponse(as, client, response, ignoreIdT
|
|
|
994
994
|
if (Array.isArray(claims.aud) && claims.aud.length !== 1 && claims.azp !== client.client_id) {
|
|
995
995
|
throw new OPE('unexpected ID Token "azp" (authorized party) claim value');
|
|
996
996
|
}
|
|
997
|
-
if (
|
|
998
|
-
|
|
997
|
+
if (claims.auth_time !== undefined &&
|
|
998
|
+
(!Number.isFinite(claims.auth_time) || Math.sign(claims.auth_time) !== 1)) {
|
|
999
|
+
throw new OPE('ID Token "auth_time" (authentication time) must be a positive number');
|
|
999
1000
|
}
|
|
1000
1001
|
idTokenClaims.set(json, claims);
|
|
1001
1002
|
}
|
|
@@ -1584,8 +1585,9 @@ export async function validateDetachedSignatureResponse(as, client, parameters,
|
|
|
1584
1585
|
(await idTokenHashMatches(expectedState, claims.s_hash, header.alg, key)) !== true)) {
|
|
1585
1586
|
throw new OPE('invalid ID Token "s_hash" (state hash) claim value');
|
|
1586
1587
|
}
|
|
1587
|
-
if (
|
|
1588
|
-
|
|
1588
|
+
if (claims.auth_time !== undefined &&
|
|
1589
|
+
(!Number.isFinite(claims.auth_time) || Math.sign(claims.auth_time) !== 1)) {
|
|
1590
|
+
throw new OPE('ID Token "auth_time" (authentication time) must be a positive number');
|
|
1589
1591
|
}
|
|
1590
1592
|
maxAge ?? (maxAge = client.default_max_age ?? skipAuthTimeCheck);
|
|
1591
1593
|
if ((client.require_auth_time || maxAge !== skipAuthTimeCheck) &&
|
|
@@ -1798,7 +1800,7 @@ export async function generateKeyPair(alg, options) {
|
|
|
1798
1800
|
if (!validateString(alg)) {
|
|
1799
1801
|
throw new TypeError('"alg" must be a non-empty string');
|
|
1800
1802
|
}
|
|
1801
|
-
const algorithm = algToSubtle(alg, alg === 'EdDSA' ? options?.crv ?? 'Ed25519' : undefined);
|
|
1803
|
+
const algorithm = algToSubtle(alg, alg === 'EdDSA' ? (options?.crv ?? 'Ed25519') : undefined);
|
|
1802
1804
|
if (alg.startsWith('PS') || alg.startsWith('RS')) {
|
|
1803
1805
|
Object.assign(algorithm, {
|
|
1804
1806
|
modulusLength: options?.modulusLength ?? 2048,
|
|
@@ -1961,5 +1963,6 @@ export const experimentalCustomFetch = customFetch;
|
|
|
1961
1963
|
export const experimental_customFetch = customFetch;
|
|
1962
1964
|
export const experimentalUseMtlsAlias = useMtlsAlias;
|
|
1963
1965
|
export const experimental_useMtlsAlias = useMtlsAlias;
|
|
1964
|
-
export const experimental_validateDetachedSignatureResponse = validateDetachedSignatureResponse;
|
|
1965
|
-
export const experimental_validateJwtAccessToken = validateJwtAccessToken;
|
|
1966
|
+
export const experimental_validateDetachedSignatureResponse = (...args) => validateDetachedSignatureResponse(...args);
|
|
1967
|
+
export const experimental_validateJwtAccessToken = (...args) => validateJwtAccessToken(...args);
|
|
1968
|
+
export const experimental_jwksCache = jwksCache;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth4webapi",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "OAuth 2 / OpenID Connect for JavaScript Runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"access token",
|
|
@@ -67,29 +67,28 @@
|
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@koa/cors": "^5.0.0",
|
|
69
69
|
"@types/koa__cors": "^5.0.0",
|
|
70
|
-
"@types/node": "^20.14.
|
|
71
|
-
"@types/oidc-provider": "^8.4.4",
|
|
70
|
+
"@types/node": "^20.14.15",
|
|
72
71
|
"@types/qunit": "^2.19.10",
|
|
73
72
|
"archiver": "^7.0.1",
|
|
74
73
|
"ava": "^6.1.3",
|
|
75
74
|
"chrome-launcher": "^1.1.2",
|
|
76
|
-
"edge-runtime": "^
|
|
77
|
-
"esbuild": "^0.
|
|
78
|
-
"jose": "^5.
|
|
79
|
-
"oidc-provider": "^8.
|
|
75
|
+
"edge-runtime": "^3.0.1",
|
|
76
|
+
"esbuild": "^0.23.1",
|
|
77
|
+
"jose": "^5.6.3",
|
|
78
|
+
"oidc-provider": "^8.5.1",
|
|
80
79
|
"patch-package": "^8.0.0",
|
|
81
|
-
"prettier": "^3.3.
|
|
80
|
+
"prettier": "^3.3.3",
|
|
82
81
|
"prettier-plugin-jsdoc": "^1.3.0",
|
|
83
|
-
"puppeteer-core": "^
|
|
84
|
-
"qunit": "^2.21.
|
|
85
|
-
"raw-body": "^
|
|
82
|
+
"puppeteer-core": "^23.1.0",
|
|
83
|
+
"qunit": "^2.21.1",
|
|
84
|
+
"raw-body": "^3.0.0",
|
|
86
85
|
"selfsigned": "^2.4.1",
|
|
87
86
|
"timekeeper": "^2.3.1",
|
|
88
|
-
"tsx": "^4.
|
|
89
|
-
"typedoc": "^0.
|
|
90
|
-
"typedoc-plugin-markdown": "^
|
|
91
|
-
"typedoc-plugin-mdn-links": "^3.
|
|
92
|
-
"typescript": "~5.4
|
|
93
|
-
"undici": "^6.19.
|
|
87
|
+
"tsx": "^4.16.5",
|
|
88
|
+
"typedoc": "^0.26.6",
|
|
89
|
+
"typedoc-plugin-markdown": "^4.2.5",
|
|
90
|
+
"typedoc-plugin-mdn-links": "^3.2.9",
|
|
91
|
+
"typescript": "~5.5.4",
|
|
92
|
+
"undici": "^6.19.7"
|
|
94
93
|
}
|
|
95
94
|
}
|