@okta/auth-foundation 0.6.0 → 0.9.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 +136 -0
- package/claude.md +256 -0
- package/dist/esm/Credential/Credential.js +17 -14
- package/dist/esm/Credential/Credential.js.map +1 -1
- package/dist/esm/Credential/CredentialCoordinator.js +6 -2
- package/dist/esm/Credential/CredentialCoordinator.js.map +1 -1
- package/dist/esm/Credential/CredentialDataSource.js +6 -4
- package/dist/esm/Credential/CredentialDataSource.js.map +1 -1
- package/dist/esm/Credential/TokenStorage.js +3 -0
- package/dist/esm/Credential/TokenStorage.js.map +1 -1
- package/dist/esm/FetchClient.js +5 -1
- package/dist/esm/FetchClient.js.map +1 -1
- package/dist/esm/Token.js +1 -0
- package/dist/esm/Token.js.map +1 -1
- package/dist/esm/TokenOrchestrator.js +4 -1
- package/dist/esm/TokenOrchestrator.js.map +1 -1
- package/dist/esm/http/APIClient.js +4 -0
- package/dist/esm/http/APIClient.js.map +1 -1
- package/dist/esm/http/oktaUserAgent.js +1 -1
- package/dist/esm/http/requests/APIRequest.js.map +1 -1
- package/dist/esm/http/requests/OAuth2Request.js.map +1 -1
- package/dist/esm/http/wwwAuthenticate.js.map +1 -1
- package/dist/esm/jwt/IDTokenValidator.js +3 -0
- package/dist/esm/jwt/IDTokenValidator.js.map +1 -1
- package/dist/esm/jwt/JWK.js.map +1 -1
- package/dist/esm/jwt/JWT.js.map +1 -1
- package/dist/esm/jwt/TokenHashValidator.js.map +1 -1
- package/dist/esm/oauth2/client.js +14 -9
- package/dist/esm/oauth2/client.js.map +1 -1
- package/dist/esm/oauth2/configuration.js +7 -3
- package/dist/esm/oauth2/configuration.js.map +1 -1
- package/dist/esm/oauth2/dpop/index.js.map +1 -1
- package/dist/esm/oauth2/dpop/nonceCache.js.map +1 -1
- package/dist/esm/oauth2/dpop/storage.js.map +1 -1
- package/dist/esm/oauth2/pkce.js.map +1 -1
- package/dist/esm/oauth2/requests/UserInfo.js.map +1 -1
- package/dist/esm/platform/Platform.js.map +1 -1
- package/dist/esm/platform/defaults.js.map +1 -1
- package/dist/esm/types/oauth.js.map +1 -1
- package/dist/esm/utils/EventEmitter.js +29 -1
- package/dist/esm/utils/EventEmitter.js.map +1 -1
- package/dist/esm/utils/TaskBridge.js +13 -0
- package/dist/esm/utils/TaskBridge.js.map +1 -1
- package/dist/esm/utils/TimeCoordinator.js.map +1 -1
- package/dist/esm/utils/merge.js.map +1 -1
- package/dist/esm/utils/pause.js.map +1 -1
- package/dist/types/Credential/Credential.d.ts +38 -21
- package/dist/types/Credential/CredentialCoordinator.d.ts +10 -3
- package/dist/types/Credential/CredentialDataSource.d.ts +2 -1
- package/dist/types/Credential/TokenStorage.d.ts +13 -2
- package/dist/types/FetchClient.d.ts +26 -5
- package/dist/types/Token.d.ts +23 -11
- package/dist/types/TokenOrchestrator.d.ts +61 -11
- package/dist/types/http/APIClient.d.ts +220 -8
- package/dist/types/http/index.d.ts +5 -0
- package/dist/types/http/requests/APIRequest.d.ts +28 -2
- package/dist/types/http/requests/OAuth2Request.d.ts +12 -2
- package/dist/types/http/wwwAuthenticate.d.ts +10 -2
- package/dist/types/jwt/IDTokenValidator.d.ts +46 -3
- package/dist/types/jwt/JWK.d.ts +35 -0
- package/dist/types/jwt/JWT.d.ts +126 -4
- package/dist/types/jwt/TokenHashValidator.d.ts +6 -0
- package/dist/types/oauth2/client.d.ts +95 -11
- package/dist/types/oauth2/configuration.d.ts +81 -7
- package/dist/types/oauth2/dpop/index.d.ts +10 -5
- package/dist/types/oauth2/dpop/nonceCache.d.ts +18 -0
- package/dist/types/oauth2/dpop/storage.d.ts +1 -0
- package/dist/types/oauth2/dpop/types.d.ts +7 -0
- package/dist/types/oauth2/pkce.d.ts +19 -0
- package/dist/types/oauth2/requests/UserInfo.d.ts +2 -1
- package/dist/types/platform/Platform.d.ts +51 -3
- package/dist/types/platform/defaults.d.ts +1 -0
- package/dist/types/types/lib.d.ts +16 -2
- package/dist/types/types/oauth.d.ts +5 -5
- package/dist/types/types/openid.d.ts +50 -234
- package/dist/types/utils/EventEmitter.d.ts +84 -2
- package/dist/types/utils/TaskBridge.d.ts +9 -1
- package/dist/types/utils/TimeCoordinator.d.ts +2 -0
- package/dist/types/utils/merge.d.ts +2 -0
- package/dist/types/utils/pause.d.ts +1 -0
- package/package.json +1 -1
package/dist/types/Token.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GrantType, type Expires, type TokenType, type RequestAuthorizer, type RequestAuthorizerInit, type Seconds, type JSONSerializable, type AcrValues, type TimeInterval, type JsonPrimitive, type JsonRecord } from './types/index.ts';
|
|
2
2
|
import type { OAuth2Client } from './oauth2/client.ts';
|
|
3
|
+
import type { OAuth2ClientOptions } from './oauth2/configuration.ts';
|
|
3
4
|
import { JWT } from './jwt/index.ts';
|
|
4
5
|
import { OAuth2Request } from './http/index.ts';
|
|
5
6
|
/**
|
|
@@ -23,6 +24,7 @@ export type TokenResponse = {
|
|
|
23
24
|
/**
|
|
24
25
|
* Required and optional values to construct a {@link Token} instance
|
|
25
26
|
* @group Types
|
|
27
|
+
* @useDeclaredType
|
|
26
28
|
*/
|
|
27
29
|
export type TokenInit = Omit<TokenResponse, 'idToken'> & {
|
|
28
30
|
idToken?: string | JWT;
|
|
@@ -36,11 +38,9 @@ export type TokenPrimitiveInit = TokenResponse;
|
|
|
36
38
|
* Internal representation of a OAuth2/OIDC Token.
|
|
37
39
|
* Contains `accessToken`, conditionally contains `idToken` and `refreshToken`
|
|
38
40
|
*
|
|
39
|
-
* @group Token
|
|
40
|
-
*
|
|
41
41
|
* @remarks
|
|
42
42
|
* Most operations can be done by {@link Credential} methods. It's recommended
|
|
43
|
-
* to use those instead before reaching for a {@link Token
|
|
43
|
+
* to use those instead before reaching for a {@link Token} method
|
|
44
44
|
*
|
|
45
45
|
* @see
|
|
46
46
|
* - Okta Documentation: {@link https://developer.okta.com/docs/reference/api/oidc/#response-properties-4 | OIDC }
|
|
@@ -95,6 +95,9 @@ export declare class Token implements JSONSerializable, Expires, RequestAuthoriz
|
|
|
95
95
|
protected static create<T extends Token>(this: new (init: TokenInit) => T, init: TokenInit): T;
|
|
96
96
|
static serializer(t: object): string;
|
|
97
97
|
static isEqual(lhs: Token, rhs: Token): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Performs a token refresh using the provided `refreshToken`
|
|
100
|
+
*/
|
|
98
101
|
static from(refreshToken: string, client: OAuth2Client): Promise<Token>;
|
|
99
102
|
/**
|
|
100
103
|
* When the Token will expire, represented as a `Date`
|
|
@@ -107,19 +110,19 @@ export declare class Token implements JSONSerializable, Expires, RequestAuthoriz
|
|
|
107
110
|
*/
|
|
108
111
|
get isExpired(): boolean;
|
|
109
112
|
/**
|
|
110
|
-
* Returns `true` if the {@link Token
|
|
113
|
+
* Returns `true` if the {@link Token:class | Token} is _not_ expired
|
|
111
114
|
*
|
|
112
115
|
* @see {@link Token.isExpired}
|
|
113
116
|
*/
|
|
114
117
|
get isValid(): boolean;
|
|
115
118
|
/**
|
|
116
|
-
* Returns `true` if the {@link Token
|
|
119
|
+
* Returns `true` if the {@link Token:class | Token} will expire after a duration (seconds)
|
|
117
120
|
*
|
|
118
121
|
* @see {@link Token.willBeValidIn}
|
|
119
122
|
*/
|
|
120
123
|
willBeExpiredIn(duration: Seconds): boolean;
|
|
121
124
|
/**
|
|
122
|
-
* Returns `true` if the {@link Token
|
|
125
|
+
* Returns `true` if the {@link Token:class | Token} will _not_ expire after a duration (seconds)
|
|
123
126
|
*
|
|
124
127
|
* @see {@link Token.willBeExpiredIn}
|
|
125
128
|
*/
|
|
@@ -129,15 +132,15 @@ export declare class Token implements JSONSerializable, Expires, RequestAuthoriz
|
|
|
129
132
|
*/
|
|
130
133
|
get scopes(): string[];
|
|
131
134
|
/**
|
|
132
|
-
* Converts a {@link Token
|
|
135
|
+
* Converts a {@link Token:class | Token} instance to an serializable object literal representation
|
|
133
136
|
*/
|
|
134
137
|
toJSON(): JsonRecord;
|
|
135
138
|
/**
|
|
136
|
-
* Used to merge separate {@link Token
|
|
139
|
+
* Used to merge separate {@link Token:class | Token} instances together. Useful when handling token refresh as
|
|
137
140
|
* not every value is returned in a refresh request compared to the initial token request
|
|
138
141
|
*
|
|
139
142
|
* @param token the "old" token instance to be merged into the "new" token
|
|
140
|
-
* @returns new {@link Token
|
|
143
|
+
* @returns new {@link Token:class | Token} instance
|
|
141
144
|
*/
|
|
142
145
|
merge(token: Token): Token;
|
|
143
146
|
serialize(): string;
|
|
@@ -163,6 +166,7 @@ export declare namespace Token {
|
|
|
163
166
|
dpopPairId?: string;
|
|
164
167
|
acrValues?: AcrValues;
|
|
165
168
|
maxAge?: TimeInterval;
|
|
169
|
+
clientSettings?: OAuth2ClientOptions;
|
|
166
170
|
};
|
|
167
171
|
/**
|
|
168
172
|
* Utility function for extracting {@link Token.Context} from an union-type object like {@link Token.Metadata:TYPE | Token.Metadata}
|
|
@@ -171,8 +175,8 @@ export declare namespace Token {
|
|
|
171
175
|
[key: string]: unknown;
|
|
172
176
|
}): Token.Context;
|
|
173
177
|
/**
|
|
174
|
-
* Non-sensitive metadata
|
|
175
|
-
* metadata for a given {@link Token
|
|
178
|
+
* Non-sensitive metadata associated with a {@link Token:class | Token}. Used to store {@link Token.Context} and additional
|
|
179
|
+
* metadata for a given {@link Token:class | Token}
|
|
176
180
|
* {@label TYPE}
|
|
177
181
|
*/
|
|
178
182
|
type Metadata = Context & {
|
|
@@ -180,6 +184,9 @@ export declare namespace Token {
|
|
|
180
184
|
tags: string[];
|
|
181
185
|
claims?: JsonRecord;
|
|
182
186
|
};
|
|
187
|
+
/**
|
|
188
|
+
* Returns {@link Metadata:type | Token.Metadata} for a given {@link Token:class | Token}
|
|
189
|
+
*/
|
|
183
190
|
function Metadata(token: Token, tags?: string[]): Metadata;
|
|
184
191
|
/** @internal */
|
|
185
192
|
interface TokenRequestParams extends OAuth2Request.RequestParams {
|
|
@@ -210,6 +217,10 @@ export declare namespace Token {
|
|
|
210
217
|
}
|
|
211
218
|
/**
|
|
212
219
|
* Possible values provided to {@link OAuth2.OAuth2Client.revoke | OAuth2Client.revoke} to determine which tokens to revoke
|
|
220
|
+
* * `'ALL'` - revokes both the `access_token` and `refresh_token`.
|
|
221
|
+
* * `'ACCESS'` - revokes **only** the `access_token`.
|
|
222
|
+
* * `'REFRESH'` - revokes **only** the `refresh_token`.
|
|
223
|
+
* @inline
|
|
213
224
|
*/
|
|
214
225
|
type RevokeType = 'ALL' | 'ACCESS' | 'REFRESH';
|
|
215
226
|
/** @internal */
|
|
@@ -224,6 +235,7 @@ export declare namespace Token {
|
|
|
224
235
|
}
|
|
225
236
|
/**
|
|
226
237
|
* Possible values provided to {@link OAuth2.OAuth2Client.introspect | OAuth2Client.introspect} to determine which token to introspect
|
|
238
|
+
* @inline
|
|
227
239
|
*/
|
|
228
240
|
type Kind = 'access_token' | 'refresh_token' | 'id_token';
|
|
229
241
|
/** @internal */
|
|
@@ -1,19 +1,50 @@
|
|
|
1
|
-
import type { RequestAuthorizer, RequestAuthorizerInit, JsonRecord, AcrValues } from './types/index.ts';
|
|
2
|
-
import { Token } from './Token.ts';
|
|
3
|
-
import { EventEmitter } from './utils/EventEmitter.ts';
|
|
4
1
|
/**
|
|
5
2
|
* @module TokenOrchestrator
|
|
6
3
|
*/
|
|
4
|
+
import type { RequestAuthorizerInit, JsonRecord, AcrValues } from './types/index.ts';
|
|
5
|
+
import { Token } from './Token.ts';
|
|
6
|
+
import { EventEmitter } from './utils/EventEmitter.ts';
|
|
7
7
|
/**
|
|
8
|
-
* @
|
|
8
|
+
* An abstraction layer between {@link Token} consumers and an application's internal management of {@link Token}s.
|
|
9
|
+
* Implementations of {@link TokenOrchestrator} handle fetching, refreshing, and storing tokens. There is an expectation
|
|
10
|
+
* (but not enforced by code) that tokens provided by {@link TokenOrchestrator} methods are valid (not expired).
|
|
11
|
+
*
|
|
12
|
+
* Consumers simply call {@link TokenOrchestrator.getToken} (or {@link TokenOrchestrator.authorize}) to use tokens as needed.
|
|
9
13
|
*
|
|
10
|
-
*
|
|
14
|
+
* @typeParam E - Map of all events fired from {@link TokenOrchestrator.emitter}
|
|
11
15
|
*
|
|
12
|
-
* @
|
|
16
|
+
* @remarks
|
|
17
|
+
* // TODO
|
|
18
|
+
* Each [Platform Library](/docs/structure#tier-3) offers {@link TokenOrchestrator} implementations relevant to the corresponding platform.
|
|
19
|
+
*
|
|
20
|
+
* @see
|
|
21
|
+
* * Orchestrator Consumer Example: {@link FetchClient}
|
|
13
22
|
*/
|
|
14
|
-
export declare abstract class TokenOrchestrator<E extends TokenOrchestrator.Events = TokenOrchestrator.Events>
|
|
23
|
+
export declare abstract class TokenOrchestrator<E extends TokenOrchestrator.Events = TokenOrchestrator.Events> {
|
|
24
|
+
/**
|
|
25
|
+
* Possible events: {@link TokenOrchestrator.Events}
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* To add a new event within a derived class, first extend {@link TokenOrchestrator.Events}, like so:
|
|
29
|
+
* ```ts
|
|
30
|
+
* type MyOrchestratorEvents = { 'no_token': { params: any } } & TokenOrchestrator.Events;
|
|
31
|
+
*
|
|
32
|
+
* class MyTokenOrchestrator<E extends MyOrchestratorEvents = MyOrchestratorEvents> extends TokenOrchestrator<E> {
|
|
33
|
+
* protected async getToken (params: TokenOrchestrator.AuthorizeParams): Promise<Token | null> {
|
|
34
|
+
* const token = this.findTokenInStorage(params); // example method
|
|
35
|
+
* if (token === null) {
|
|
36
|
+
* // this `.emit` call will be properly typed
|
|
37
|
+
* this.emitter.emit('no_token', params);
|
|
38
|
+
* }
|
|
39
|
+
* return token;
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
15
44
|
protected readonly emitter: EventEmitter<E>;
|
|
45
|
+
/** alias for `this.emitter.on` */
|
|
16
46
|
on(...args: Parameters<EventEmitter<E>['on']>): EventEmitter<E>;
|
|
47
|
+
/** alias for `this.emitter.off` */
|
|
17
48
|
off(...args: Parameters<EventEmitter<E>['off']>): EventEmitter<E>;
|
|
18
49
|
/**
|
|
19
50
|
* @abstract
|
|
@@ -22,15 +53,34 @@ export declare abstract class TokenOrchestrator<E extends TokenOrchestrator.Even
|
|
|
22
53
|
*/
|
|
23
54
|
abstract getToken(params: TokenOrchestrator.AuthorizeParams): Promise<Token | null>;
|
|
24
55
|
/**
|
|
25
|
-
*
|
|
56
|
+
* @abstract
|
|
57
|
+
* Invalidates a {@link Token.Token | Token}, so subsequent {@link TokenOrchestrator.getToken | getToken} calls will result in the invalidated token
|
|
58
|
+
*/
|
|
59
|
+
abstract invalidateToken(id: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Signs an outgoing {@link !Request} with an `Authorization` header via {@link Token | Token} retrieved from {@link getToken}
|
|
26
62
|
*
|
|
27
63
|
* Optionally {@link TokenOrchestrator.AuthorizeParams | AuthorizeParams} can be provided to be passed along to {@link getToken}
|
|
28
|
-
*
|
|
29
|
-
* @see {@link FetchClient}
|
|
30
64
|
*/
|
|
31
|
-
authorize(input: string | URL | Request, init?: RequestAuthorizerInit & TokenOrchestrator.AuthorizeParams): Promise<
|
|
65
|
+
authorize(input: string | URL | Request, init?: RequestAuthorizerInit & TokenOrchestrator.AuthorizeParams): Promise<{
|
|
66
|
+
request: Request;
|
|
67
|
+
tokenId: string;
|
|
68
|
+
}>;
|
|
32
69
|
}
|
|
33
70
|
export declare namespace TokenOrchestrator {
|
|
71
|
+
/**
|
|
72
|
+
* @interface
|
|
73
|
+
* Map of events fired from {@link TokenOrchestrator.emitter}
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* // key = Event name
|
|
78
|
+
* // value = Event Type
|
|
79
|
+
* client.emitter.on('error', ({ error }) => {
|
|
80
|
+
* console.log(error);
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
34
84
|
type Events = {
|
|
35
85
|
error: {
|
|
36
86
|
error: Error | JsonRecord;
|
|
@@ -10,85 +10,292 @@ import { APIClientError } from '../errors/index.ts';
|
|
|
10
10
|
export * from './requests/APIRequest.ts';
|
|
11
11
|
export * from './requests/OAuth2Request.ts';
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Generic HTTP client with built in request retry
|
|
14
|
+
* @typeParam E - Map of all events fired from {@link APIClient.emitter}
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* To add an event within a derived class, first extend {@link APIClient.Events}, like so:
|
|
18
|
+
* ```ts
|
|
19
|
+
* type MyAPIEvents = { 'foo': { bar: number } } & APIClient.Events;
|
|
20
|
+
*
|
|
21
|
+
* class MyAPIClient<E extends MyAPIEvents = MyAPIEvents> extends APIClient<E> {
|
|
22
|
+
* protected async send (request: APIRequest): Promise<Response> {
|
|
23
|
+
* // this will be properly type checked
|
|
24
|
+
* this.emitter('foo', { bar: 1 });
|
|
25
|
+
* return super.send(request);
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @remarks Most application developers won't need to extend this class directly — reach for
|
|
31
|
+
* {@link OAuth2.OAuth2Client | OAuth2Client} or {@link FetchClient} instead
|
|
14
32
|
*/
|
|
15
33
|
export declare abstract class APIClient<E extends APIClient.Events = APIClient.Events> {
|
|
16
34
|
#private;
|
|
17
35
|
readonly configuration: APIClient.Configuration;
|
|
36
|
+
/**
|
|
37
|
+
* Possible events: {@link APIClient.Events}
|
|
38
|
+
*/
|
|
18
39
|
readonly emitter: EventEmitter<E>;
|
|
40
|
+
/**
|
|
41
|
+
* A cache of `dpop-nonce` values returned by authorization or resource servers.
|
|
42
|
+
* The cached nonce values will be used when generating DPoP JWTs for outgoing requests.
|
|
43
|
+
* @remarks Only relevant if client is configured with `dpop: true`
|
|
44
|
+
*/
|
|
19
45
|
protected readonly dpopNonceCache: DPoPNonceCache;
|
|
46
|
+
/** @internal */
|
|
20
47
|
protected readonly interceptors: APIClient.RequestInterceptor[];
|
|
48
|
+
/** Map of HTTP headers to apply to every request */
|
|
21
49
|
defaultHeaders: Record<string, string>;
|
|
50
|
+
/** Default {@link APIClient.RequestOptions} to apply to every request */
|
|
22
51
|
defaultRequestOptions: APIClient.RequestOptions;
|
|
23
52
|
constructor(params?: APIClient.ConfigurationParams | APIClient.Configuration);
|
|
53
|
+
/**
|
|
54
|
+
* Returns a key for a giving request to store or retrieve nonce values from the {@link APIClient.dpopNonceCache}
|
|
55
|
+
* @group DPoP
|
|
56
|
+
*/
|
|
24
57
|
protected getDPoPNonceCacheKey(request: Request): string;
|
|
58
|
+
/**
|
|
59
|
+
* Retrieves a nonce value from the {@link APIClient.dpopNonceCache}
|
|
60
|
+
* @group DPoP
|
|
61
|
+
*/
|
|
25
62
|
protected getDPoPNonceFromCache(request: Request): Promise<string | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Caches an incoming nonce value from the {@link APIClient.dpopNonceCache}
|
|
65
|
+
* @group DPoP
|
|
66
|
+
*/
|
|
26
67
|
protected cacheDPoPNonce(request: Request, nonce: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Cleans up resources associated with the client instance, so that it may be garbage collected.
|
|
70
|
+
*
|
|
71
|
+
* > [!Warning]
|
|
72
|
+
* > **DO NOT** use this method on active clients.
|
|
73
|
+
*
|
|
74
|
+
* @internal
|
|
75
|
+
*/
|
|
76
|
+
dispose(): void;
|
|
27
77
|
/**
|
|
28
78
|
* Registers an {@link APIClient.RequestInterceptor} on the {@link APIClient}
|
|
29
79
|
*
|
|
30
80
|
* @example
|
|
81
|
+
* ```ts
|
|
31
82
|
* const interceptor = (request: Request) => {
|
|
32
83
|
* req.headers.append('foo', '1');
|
|
33
84
|
* return req;
|
|
34
85
|
* };
|
|
35
86
|
* client.addInterceptor(interceptor);
|
|
87
|
+
* ```
|
|
88
|
+
* @group Interceptors
|
|
36
89
|
*/
|
|
37
90
|
addInterceptor(interceptor: APIClient.RequestInterceptor): void;
|
|
38
91
|
/**
|
|
39
92
|
* Unregisters an {@link APIClient.RequestInterceptor} on the {@link APIClient}
|
|
40
93
|
*
|
|
41
94
|
* @example
|
|
95
|
+
* ```ts
|
|
42
96
|
* const interceptor = (request: Request) => { ... };
|
|
43
97
|
* client.addInterceptor(interceptor);
|
|
44
98
|
* ...
|
|
45
99
|
* client.removeInterceptor(interceptor);
|
|
100
|
+
* ```
|
|
101
|
+
* @group Interceptors
|
|
46
102
|
*/
|
|
47
103
|
removeInterceptor(interceptor: APIClient.RequestInterceptor): void;
|
|
104
|
+
/**
|
|
105
|
+
* @group Interceptors
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
48
108
|
protected applyInterceptors(request: APIRequest): Promise<Request>;
|
|
109
|
+
/**
|
|
110
|
+
* Determines if a {@link !Response} indicates a DPoP nonce error. If error is present, returns
|
|
111
|
+
* the value of the `dpop-nonce` response header.
|
|
112
|
+
*
|
|
113
|
+
* @group DPoP
|
|
114
|
+
* @remarks
|
|
115
|
+
* * {@link OAuth2.OAuth2Client} provides an authorization server-provided nonce implementation
|
|
116
|
+
* * {@link FetchClient} provides an resource server-provided nonce implementation
|
|
117
|
+
*
|
|
118
|
+
* @see
|
|
119
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc9449#section-11.3 | RFC 9449 - DPoP Nonce Downgrade}
|
|
120
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc9449#section-8 | RFC 9449 - Authorization Server-Provided Nonce}
|
|
121
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc9449#section-9 | RFC 9449 - Resource Server-Provided Nonce}
|
|
122
|
+
*/
|
|
49
123
|
protected abstract checkForDPoPNonceErrorResponse(response: Response): Promise<string | undefined>;
|
|
124
|
+
/**
|
|
125
|
+
* Prepares an {@link APIRequest} for a retry with a new `dpop-nonce` value
|
|
126
|
+
*
|
|
127
|
+
* @group DPoP
|
|
128
|
+
*
|
|
129
|
+
* @see
|
|
130
|
+
* * {@link APIClient.checkForDPoPNonceErrorResponse}
|
|
131
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc9449#section-8 | RFC 9449 - Authorization Server-Provided Nonce}
|
|
132
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc9449#section-9 | RFC 9449 - Resource Server-Provided Nonce}
|
|
133
|
+
*/
|
|
50
134
|
protected abstract prepareDPoPNonceRetry(request: APIRequest, nonce: string): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Called on every {@link !Response} received.
|
|
137
|
+
*/
|
|
51
138
|
protected processResponse(response: Response, request: APIRequest): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Called on every {@link !Response} where `response.ok` is `false`
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* When processing a {@link !Response}, `processErrorResponse` may invoke {@link APIClient.retry}. Therefore, when extending
|
|
144
|
+
* `APIClient` and calling `super.processErrorResponse` the same error condition could be handled twice erroneously.<br/>
|
|
145
|
+
* To prevent this, check if the parameter `response` and the return value of `super.processErrorResponse` are equal (the
|
|
146
|
+
* same {@link !Response} instance). If they are not equal, the `response` was already retried.
|
|
147
|
+
* ```ts
|
|
148
|
+
* class MyAPIClient extends APIClient {
|
|
149
|
+
* protected async processErrorResponse (response: Response, request: APIRequest): Promise<Response> {
|
|
150
|
+
* const res = await super.processErrorResponse(response, request);
|
|
151
|
+
* if (response !== res) {
|
|
152
|
+
* // response was already retried, return new `Response` instance.
|
|
153
|
+
* return res;
|
|
154
|
+
* }
|
|
155
|
+
* response = res;
|
|
156
|
+
*
|
|
157
|
+
* // handle other scenarios here
|
|
158
|
+
*
|
|
159
|
+
* return response;
|
|
160
|
+
* }
|
|
161
|
+
* }
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
52
164
|
protected processErrorResponse(response: Response, request: APIRequest): Promise<Response>;
|
|
165
|
+
/**
|
|
166
|
+
* @abstract
|
|
167
|
+
* Signs an outgoing {@link APIRequest} with required authentication information.
|
|
168
|
+
*
|
|
169
|
+
* This method is marked as `abstract` since not every API requires authentication.
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* Most implementations of this method usually invoke {@link Token.Token.authorize | Token.authorize}
|
|
173
|
+
*/
|
|
53
174
|
protected authorize(request: APIRequest): Promise<void>;
|
|
175
|
+
/**
|
|
176
|
+
* **Do not call directly** use {@link APIClient.send}.
|
|
177
|
+
*
|
|
178
|
+
* This method provides an alternative means to provide a custom {@link fetch} implementation. By default,
|
|
179
|
+
* this method invokes {@link APIClient.Configuration.fetchImpl | .fetchImpl} and falls back to `globalThis.fetch`
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* class MyAPIClient extends APIClient {
|
|
184
|
+
* protected sendRequest (request: Request): Promise<Response> {
|
|
185
|
+
* return customFetch(request);
|
|
186
|
+
* }
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
54
190
|
protected sendRequest(request: Request): Promise<Response>;
|
|
191
|
+
/**
|
|
192
|
+
* Sends an outgoing {@link APIRequest} and processes the {@link !Response}.
|
|
193
|
+
*
|
|
194
|
+
* @remarks
|
|
195
|
+
* It's **NOT** recommended to override this method, as it contains the majority of the business logic
|
|
196
|
+
*/
|
|
55
197
|
protected send(request: APIRequest): Promise<Response>;
|
|
198
|
+
/**
|
|
199
|
+
* Prepares a {@link APIRequest} for a retry attempt and sends the retry request. Usually invoked within
|
|
200
|
+
* {@link APIClient.processErrorResponse}
|
|
201
|
+
*/
|
|
56
202
|
protected retry(request: APIRequest): Promise<Response>;
|
|
203
|
+
/**
|
|
204
|
+
* Calculates a delay to wait before retrying a {@link APIRequest} which previously responded with `429`.
|
|
205
|
+
* Useful for rate limited APIs.
|
|
206
|
+
*/
|
|
57
207
|
protected getRetryDelay(response: Response, request: APIRequest): number;
|
|
208
|
+
/**
|
|
209
|
+
* A `public` method to expose {@link APIClient.send}
|
|
210
|
+
* @param args - matches call signature of {@link !fetch}
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* class MyAPIClient extends APIClient {...}
|
|
215
|
+
* const client = new MyAPIClient();
|
|
216
|
+
*
|
|
217
|
+
* async function fetchData () {
|
|
218
|
+
* return client.fetch('/foo');
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
58
222
|
fetch(...args: ConstructorParameters<typeof APIRequest>): Promise<Response>;
|
|
59
223
|
}
|
|
60
|
-
/**
|
|
61
|
-
* @group APIClient
|
|
62
|
-
*/
|
|
63
224
|
export declare namespace APIClient {
|
|
225
|
+
/**
|
|
226
|
+
* Options to provide to {@link Configuration} at instantiation
|
|
227
|
+
*/
|
|
64
228
|
type ConfigurationParams = {
|
|
65
229
|
dpop?: boolean;
|
|
66
230
|
fetchImpl?: typeof fetch;
|
|
67
231
|
};
|
|
68
232
|
class Configuration implements JSONSerializable {
|
|
233
|
+
/**
|
|
234
|
+
* When `true`, client will utilize DPoP-bound tokens.
|
|
235
|
+
*
|
|
236
|
+
* @remarks
|
|
237
|
+
* Highly recommended feature; greatly improves security posture.
|
|
238
|
+
*
|
|
239
|
+
* @see
|
|
240
|
+
* {@link https://datatracker.ietf.org/doc/html/rfc9449 | DPoP RFC}
|
|
241
|
+
*/
|
|
69
242
|
dpop: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* Implementation of {@link !fetch} used by the client. Defaults to `globalThis.fetch`.
|
|
245
|
+
*
|
|
246
|
+
* @remarks
|
|
247
|
+
* Providing a custom {@link !fetch} implementation can enable greater HTTP request customizations.
|
|
248
|
+
*/
|
|
70
249
|
fetchImpl?: typeof fetch;
|
|
250
|
+
/**
|
|
251
|
+
* @defaultValue
|
|
252
|
+
* ```ts
|
|
253
|
+
* { dpop: false }
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
71
256
|
static DefaultOptions: {
|
|
72
257
|
dpop: boolean;
|
|
73
258
|
fetchImpl?: typeof fetch;
|
|
74
259
|
};
|
|
75
260
|
constructor(params: APIClient.ConfigurationParams);
|
|
261
|
+
/**
|
|
262
|
+
* Returns JSON representiation of {@link Configuration:class | Configuration}
|
|
263
|
+
*/
|
|
76
264
|
toJSON(): JsonRecord;
|
|
77
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Options which control how an {@link APIClient} sends a request.
|
|
268
|
+
*/
|
|
78
269
|
type RequestOptions = {
|
|
79
270
|
/**
|
|
80
|
-
*
|
|
81
|
-
* `Authorization` and `Dpop` headers, depending on the {@link TokenType} of the acquired {@link Token}. Defaults to `true`
|
|
271
|
+
* Determines whether a {@link APIRequest} should invoke {@link APIClient.authorize} before sending. Defaults to `true`
|
|
82
272
|
*/
|
|
83
273
|
authorizeRequest: boolean | ((request: APIRequest) => boolean);
|
|
84
274
|
};
|
|
275
|
+
/**
|
|
276
|
+
* Function signature for {@link APIClient} request interceptors.
|
|
277
|
+
*/
|
|
85
278
|
type RequestInterceptor = (request: APIRequest) => (Promise<APIRequest> | APIRequest);
|
|
279
|
+
/**
|
|
280
|
+
* @interface
|
|
281
|
+
* Map of events fired from {@link APIClient.emitter}
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```ts
|
|
285
|
+
* // key = Event name
|
|
286
|
+
* // value = Event Type
|
|
287
|
+
* client.emitter.on('will_send', ({ request }) => {
|
|
288
|
+
* console.log(request.url.href);
|
|
289
|
+
* });
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
86
292
|
type Events = {
|
|
87
293
|
/**
|
|
88
294
|
* Fired before a request is sent
|
|
89
295
|
*
|
|
90
296
|
* @remarks
|
|
91
|
-
* The `request` instance is `readonly`. For outgoing request customization see
|
|
297
|
+
* The `request` instance is `readonly`. For outgoing request customization see
|
|
298
|
+
* {@link Networking.APIClient.addInterceptor | APIClient.addInterceptor}
|
|
92
299
|
*/
|
|
93
300
|
'will_send': {
|
|
94
301
|
request: Request;
|
|
@@ -101,7 +308,8 @@ export declare namespace APIClient {
|
|
|
101
308
|
response: Response;
|
|
102
309
|
};
|
|
103
310
|
/**
|
|
104
|
-
* Fired after a {@link fetch} call fails to complete (
|
|
311
|
+
* Fired after a {@link fetch} call fails to complete (no response is received).
|
|
312
|
+
* Usually indicated via `TypeError: Failed to fetch`
|
|
105
313
|
*/
|
|
106
314
|
'network_failure': {
|
|
107
315
|
request: Request;
|
|
@@ -109,5 +317,9 @@ export declare namespace APIClient {
|
|
|
109
317
|
cause: Error;
|
|
110
318
|
};
|
|
111
319
|
};
|
|
320
|
+
/**
|
|
321
|
+
* Determines whether a value is an {@link !Error} indicating network connectivity problems when awaiting
|
|
322
|
+
* a {@link !fetch} request.
|
|
323
|
+
*/
|
|
112
324
|
function isNetworkError(err: unknown): boolean;
|
|
113
325
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Networking
|
|
3
|
+
*
|
|
4
|
+
* @groupDescription WWWAuthenticate
|
|
5
|
+
* A collection of utilities for parsing `www-autheticate` headers
|
|
6
|
+
* * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/WWW-Authenticate | MDN - WWW-Authenticate}
|
|
7
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc7235#section-4.1 | RFC 7235 - WWW-Authenticate}
|
|
3
8
|
*/
|
|
4
9
|
export * from './requests/OAuth2Request.ts';
|
|
5
10
|
export * from './APIClient.ts';
|
|
@@ -1,19 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith Networking
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Properties requried to construct an instance of {@link APIRequest}
|
|
3
7
|
*/
|
|
4
8
|
export type APIRequestInit = RequestInit & {
|
|
5
9
|
context?: object;
|
|
6
10
|
};
|
|
7
11
|
/**
|
|
8
|
-
* @
|
|
12
|
+
* An extension of {@link !Request} to be used within {@link APIClient}.
|
|
13
|
+
*
|
|
14
|
+
* Holds a request {@link APIRequest.context | context } and {@link APIRequest.retryAttempt | retry count}
|
|
15
|
+
*
|
|
16
|
+
* @noInheritDoc
|
|
9
17
|
*/
|
|
10
18
|
export declare class APIRequest extends Request {
|
|
11
19
|
#private;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum number of retries which are allowed to be attempted for a given {@link APIRequest}.
|
|
22
|
+
* @defaultValue 2
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Changing this value will only effect `APIRequest`s created _afterwards_. It will have no effect
|
|
26
|
+
* on any prexisting instances.
|
|
27
|
+
*/
|
|
12
28
|
static MaxRetryAttempts: number;
|
|
29
|
+
/**
|
|
30
|
+
* A map to store contextual information about the `APIRequest`, meaningful to the specific {@link APIClient}
|
|
31
|
+
*/
|
|
13
32
|
readonly context: Record<string, any>;
|
|
14
33
|
constructor(input: string | URL | Request, init?: APIRequestInit);
|
|
15
34
|
get retryAttempt(): number;
|
|
35
|
+
/**
|
|
36
|
+
* Compares the retry counter to {@link APIRequest.MaxRetryAttempts}
|
|
37
|
+
*/
|
|
16
38
|
canRetry(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Increments retry counter
|
|
41
|
+
*/
|
|
17
42
|
markRetry(): void;
|
|
43
|
+
/** @internal */
|
|
18
44
|
clone(): APIRequest;
|
|
19
45
|
}
|
|
@@ -6,25 +6,35 @@ import type { OpenIdConfiguration } from '../../types/index.ts';
|
|
|
6
6
|
import type { OAuth2Client } from '../../oauth2/client.ts';
|
|
7
7
|
import { APIRequest } from './APIRequest.ts';
|
|
8
8
|
/**
|
|
9
|
-
* @
|
|
9
|
+
* A builder class for {@link !Request} instances representing a OAuth2 endpoint request
|
|
10
|
+
* @group OAuth2Client
|
|
10
11
|
*/
|
|
11
12
|
export declare abstract class OAuth2Request {
|
|
13
|
+
/** HTTP headers for the outgoing request */
|
|
12
14
|
headers: Headers;
|
|
15
|
+
/** HTTP body for the outgoing request */
|
|
13
16
|
body: URLSearchParams;
|
|
17
|
+
/** Reference to the OAuth2 Metadata document from the authorization server */
|
|
14
18
|
openIdConfiguration: OpenIdConfiguration;
|
|
19
|
+
/** Configuration of the {@link OAuth2Client} being used to send the request */
|
|
15
20
|
clientConfiguration: OAuth2Client.Configuration;
|
|
21
|
+
/** Authentication setting for the authorization server. Only relevant to Confidental Clients */
|
|
16
22
|
clientAuthentication: any;
|
|
17
23
|
constructor(params: OAuth2Request.RequestParams);
|
|
24
|
+
/** Returns the URL of the request */
|
|
18
25
|
abstract get url(): string;
|
|
19
26
|
prepare(context?: object): APIRequest;
|
|
20
27
|
}
|
|
21
28
|
/**
|
|
22
|
-
* @group
|
|
29
|
+
* @group OAuth2Client
|
|
23
30
|
*/
|
|
24
31
|
export declare namespace OAuth2Request {
|
|
25
32
|
interface RequestParams {
|
|
33
|
+
/** Reference to the OAuth2 Metadata document from the authorization server */
|
|
26
34
|
openIdConfiguration: OpenIdConfiguration;
|
|
35
|
+
/** Configuration of the {@link OAuth2Client} being used to send the request */
|
|
27
36
|
clientConfiguration: OAuth2Client.Configuration;
|
|
37
|
+
/** Authentication setting for the authorization server. Only relevant to Confidental Clients */
|
|
28
38
|
clientAuthentication?: any;
|
|
29
39
|
}
|
|
30
40
|
}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
* @mergeModuleWith Networking
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
+
* Object representiation of a parsed `www-authenticate` header
|
|
6
7
|
* @group WWWAuthenticate
|
|
8
|
+
* @see
|
|
9
|
+
* * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/WWW-Authenticate | MDN}
|
|
10
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc7235#section-4.1 | RFC 7235 - WWW-Authenticate}
|
|
7
11
|
*/
|
|
8
12
|
export interface WWWAuthenticateError {
|
|
9
13
|
readonly error: string;
|
|
@@ -12,17 +16,21 @@ export interface WWWAuthenticateError {
|
|
|
12
16
|
[key: string]: string;
|
|
13
17
|
}
|
|
14
18
|
/**
|
|
19
|
+
* Type predicate for {@link WWWAuthenticateError}
|
|
15
20
|
* @group WWWAuthenticate
|
|
16
21
|
*/
|
|
17
22
|
export declare function isWWWAuthenticateError(input: unknown): input is WWWAuthenticateError;
|
|
18
23
|
/**
|
|
19
|
-
*
|
|
24
|
+
* Parses a `www-authenticate` header and returns an object representation of the error condition.
|
|
20
25
|
*
|
|
21
26
|
* @group WWWAuthenticate
|
|
27
|
+
* @see
|
|
28
|
+
* * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/WWW-Authenticate | MDN}
|
|
29
|
+
* * {@link https://datatracker.ietf.org/doc/html/rfc7235#section-4.1 | RFC 7235 - WWW-Authenticate}
|
|
22
30
|
*/
|
|
23
31
|
export declare function parse(header: string | Headers | Response): WWWAuthenticateError | null;
|
|
24
32
|
/**
|
|
25
|
-
* Returns string value of a `www-authenticate` header
|
|
33
|
+
* Returns string value of a `www-authenticate` header.
|
|
26
34
|
*
|
|
27
35
|
* @remarks
|
|
28
36
|
* `HeadersInit` allows for a few different representations of headers with different access patterns (.get vs [key])
|