@hyper.authio/testing 0.1.1 → 0.8.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 +36 -6
- package/dist/index.cjs +449 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +213 -9
- package/dist/index.d.ts +213 -9
- package/dist/index.js +451 -47
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -2,20 +2,86 @@ import { JWK } from 'jose';
|
|
|
2
2
|
import { AuthioClock } from '@hyper.authio/client';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* How the fake encrypts what it issues to a client, as Authio does once the client registered an encryption key.
|
|
6
|
+
*/
|
|
7
|
+
interface FakeAuthioClientEncryption {
|
|
8
|
+
/** The client's public encryption key (RSA). */
|
|
9
|
+
key: JWK;
|
|
10
|
+
/** Defaults to `RSA-OAEP-256`. */
|
|
11
|
+
algorithm?: "RSA-OAEP" | "RSA-OAEP-256";
|
|
12
|
+
/** Defaults to `A256CBC-HS512`. */
|
|
13
|
+
encryptionMethod?: "A128CBC-HS256" | "A192CBC-HS384" | "A256CBC-HS512";
|
|
14
|
+
/** Encrypts the client's access tokens (nested JWT). */
|
|
15
|
+
accessTokens?: boolean;
|
|
16
|
+
/** Encrypts the client's ID tokens. Defaults to `true`. */
|
|
17
|
+
idTokens?: boolean;
|
|
18
|
+
/** Encrypts UserInfo answered as a JWT. Defaults to `true`. */
|
|
19
|
+
userInfo?: boolean;
|
|
20
|
+
/** Encrypts back-channel logout tokens. */
|
|
21
|
+
logoutTokens?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* How a client authenticates to the token, introspection, revocation and device endpoints, as registered in Authio.
|
|
25
|
+
*/
|
|
26
|
+
type FakeAuthioTokenEndpointAuthMethod = "client_secret_basic" | "client_secret_post" | "private_key_jwt" | "none";
|
|
27
|
+
/**
|
|
28
|
+
* The algorithm Authio signs every token of a client with: the realm's RSA key, or the client secret (HS*).
|
|
29
|
+
*/
|
|
30
|
+
type FakeAuthioSigningAlgorithm = "RS256" | "HS256" | "HS384" | "HS512";
|
|
31
|
+
/**
|
|
32
|
+
* A client registered in the fake, configured as a client is in Authio's console. What the client requires is
|
|
33
|
+
* enforced as Authio enforces it: a request that does not match is refused with an error naming the setting, and
|
|
34
|
+
* what the client does not require is accepted (PKCE sent voluntarily, a secret sent by a public client).
|
|
6
35
|
*/
|
|
7
36
|
interface FakeAuthioClient {
|
|
8
37
|
clientId: string;
|
|
9
|
-
/** For `client_secret_basic` and `client_secret_post
|
|
38
|
+
/** For `client_secret_basic` and `client_secret_post`, and the key of HS* signatures. */
|
|
10
39
|
clientSecret?: string;
|
|
11
40
|
/** The public JWK `private_key_jwt` assertions are verified with. */
|
|
12
41
|
publicKey?: JWK;
|
|
42
|
+
/**
|
|
43
|
+
* How the client must authenticate; another method is refused with `invalid_client`, except a secret sent by a
|
|
44
|
+
* `none` client, which is ignored. Defaults to `client_secret_basic` with a `clientSecret`, `private_key_jwt` with
|
|
45
|
+
* only a `publicKey`, and `none` with neither.
|
|
46
|
+
*/
|
|
47
|
+
tokenEndpointAuthMethod?: FakeAuthioTokenEndpointAuthMethod;
|
|
48
|
+
/**
|
|
49
|
+
* Refuses an authorization request without `code_challenge` (Authio's "PKCE" switch). Defaults to `true`, as Authio
|
|
50
|
+
* creates clients; set `false` for a client with PKCE off.
|
|
51
|
+
*/
|
|
52
|
+
requirePkce?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The PKCE methods accepted, required or not: a `code_challenge` with another method is refused. Defaults to
|
|
55
|
+
* `["S256"]`, as Authio creates clients.
|
|
56
|
+
*/
|
|
57
|
+
pkceMethods?: ("S256" | "plain")[];
|
|
58
|
+
/**
|
|
59
|
+
* The algorithm the client's ID tokens, signed UserInfo and logout tokens are signed with. Defaults to `RS256`. HS*
|
|
60
|
+
* needs a `clientSecret` of at least 32, 48 or 64 bytes (RFC 7518 §3.2), as Authio requires.
|
|
61
|
+
*/
|
|
62
|
+
signingAlgorithm?: FakeAuthioSigningAlgorithm;
|
|
63
|
+
/** The algorithm the client's access tokens are signed with, Authio's second setting. Defaults to `RS256`. */
|
|
64
|
+
accessTokenSigningAlgorithm?: FakeAuthioSigningAlgorithm;
|
|
65
|
+
/** Issues a new ID token with every refresh. Defaults to `false`. */
|
|
66
|
+
issueIdTokenOnRefresh?: boolean;
|
|
13
67
|
/** Scopes granted when a request names none. */
|
|
14
68
|
defaultScopes?: string[];
|
|
15
69
|
/** Extra claims put into every access token issued to the client. */
|
|
16
70
|
claims?: Record<string, unknown>;
|
|
17
71
|
/** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */
|
|
18
72
|
introspectionClients?: string[];
|
|
73
|
+
/** The redirect URIs the authorization endpoint accepts. Any when absent. */
|
|
74
|
+
redirectUris?: string[];
|
|
75
|
+
/** The post-logout redirect URIs the end-session endpoint accepts. Any when absent. */
|
|
76
|
+
postLogoutRedirectUris?: string[];
|
|
77
|
+
/** Where back-channel logout tokens are posted when a session of the client ends. */
|
|
78
|
+
backchannelLogoutUri?: string;
|
|
79
|
+
/** The page loaded (here: fetched) when a session of the client ends (front-channel logout). */
|
|
80
|
+
frontchannelLogoutUri?: string;
|
|
81
|
+
/** Adds `iss` and `sid` to the front-channel logout URI. Defaults to `false`. */
|
|
82
|
+
frontchannelLogoutSessionRequired?: boolean;
|
|
83
|
+
/** Encrypts what is issued to the client. */
|
|
84
|
+
encryption?: FakeAuthioClientEncryption;
|
|
19
85
|
}
|
|
20
86
|
/**
|
|
21
87
|
* A person the fake knows, for the password grant, authorization codes and UserInfo.
|
|
@@ -28,6 +94,23 @@ interface FakeAuthioUser {
|
|
|
28
94
|
claims?: Record<string, unknown>;
|
|
29
95
|
/** What UserInfo answers besides `sub`. */
|
|
30
96
|
userInfo?: Record<string, unknown>;
|
|
97
|
+
/** The sign-in's methods. Defaults to `["pwd"]`. */
|
|
98
|
+
amr?: string[];
|
|
99
|
+
/** The sign-in's level. Defaults to `1`, or the `acr_values` asked for. */
|
|
100
|
+
acr?: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A personal access token the fake accepts with the `personal_access_token` grant.
|
|
104
|
+
*/
|
|
105
|
+
interface FakeAuthioPersonalAccessToken {
|
|
106
|
+
/** The `pat_…` value. */
|
|
107
|
+
token: string;
|
|
108
|
+
/** The credential's id, the token's `sub`. */
|
|
109
|
+
sub: string;
|
|
110
|
+
/** The consumer's client, for a consumer's token; the `authio` client of an account otherwise. */
|
|
111
|
+
clientId?: string;
|
|
112
|
+
/** Claims added to the access token. */
|
|
113
|
+
claims?: Record<string, unknown>;
|
|
31
114
|
}
|
|
32
115
|
/**
|
|
33
116
|
* An error the fake answers a request with.
|
|
@@ -45,9 +128,40 @@ interface FakeAuthioRecordedRequest {
|
|
|
45
128
|
path: string;
|
|
46
129
|
headers: Record<string, string>;
|
|
47
130
|
form: Record<string, string>;
|
|
131
|
+
/** The query parameters. */
|
|
132
|
+
query: Record<string, string>;
|
|
48
133
|
/** The client the request authenticated as, when it did. */
|
|
49
134
|
clientId?: string;
|
|
50
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* A back-channel logout token the fake posted to a client.
|
|
138
|
+
*/
|
|
139
|
+
interface FakeAuthioBackchannelDelivery {
|
|
140
|
+
clientId: string;
|
|
141
|
+
uri: string;
|
|
142
|
+
logoutToken: string;
|
|
143
|
+
/** The HTTP status the client answered, or 0 when it could not be reached. */
|
|
144
|
+
status: number;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A front-channel logout page the fake loaded for a client.
|
|
148
|
+
*/
|
|
149
|
+
interface FakeAuthioFrontchannelDelivery {
|
|
150
|
+
clientId: string;
|
|
151
|
+
/** The URL loaded, with `iss` and `sid` when the client requires the session. */
|
|
152
|
+
url: string;
|
|
153
|
+
/** The HTTP status the client answered, or 0 when it could not be reached. */
|
|
154
|
+
status: number;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The parameters an authorization ended with, as the fake sent them back.
|
|
158
|
+
*/
|
|
159
|
+
interface FakeAuthioAuthorizationOutcome {
|
|
160
|
+
/** `code`, `state` and `iss`, or `error`, `error_description`, `state` and `iss`. */
|
|
161
|
+
parameters: Record<string, string>;
|
|
162
|
+
/** The redirect URI with the parameters, for `response_mode=query`. */
|
|
163
|
+
callbackUrl: string | undefined;
|
|
164
|
+
}
|
|
51
165
|
/**
|
|
52
166
|
* What the device flow answers to successive polls.
|
|
53
167
|
*/
|
|
@@ -62,6 +176,14 @@ interface FakeAuthioOptions {
|
|
|
62
176
|
accessTokenLifetime?: number;
|
|
63
177
|
clients?: FakeAuthioClient[];
|
|
64
178
|
users?: FakeAuthioUser[];
|
|
179
|
+
personalAccessTokens?: FakeAuthioPersonalAccessToken[];
|
|
180
|
+
/**
|
|
181
|
+
* The clock tokens are issued and checked with (milliseconds since the epoch), such as the `ManualClock` the
|
|
182
|
+
* library under test uses. Defaults to the system clock.
|
|
183
|
+
*/
|
|
184
|
+
clock?: {
|
|
185
|
+
now(): number;
|
|
186
|
+
};
|
|
65
187
|
}
|
|
66
188
|
/**
|
|
67
189
|
* Options of a token minted directly.
|
|
@@ -82,34 +204,56 @@ interface FakeAuthioTokenOptions {
|
|
|
82
204
|
issuer?: string;
|
|
83
205
|
/** Signs with another key, so the signature does not verify. */
|
|
84
206
|
untrusted?: boolean;
|
|
207
|
+
/** Encrypts the token (nested JWT) to this public key, as Authio does for a client with an encryption key. */
|
|
208
|
+
encryptTo?: {
|
|
209
|
+
key: JWK;
|
|
210
|
+
algorithm?: "RSA-OAEP" | "RSA-OAEP-256";
|
|
211
|
+
encryptionMethod?: string;
|
|
212
|
+
};
|
|
85
213
|
}
|
|
214
|
+
type Endpoint = "token" | "introspect" | "revoke" | "userinfo" | "device" | "discovery" | "authorize" | "logout";
|
|
86
215
|
/**
|
|
87
|
-
* An in-memory Authio realm served over HTTP on loopback: discovery, JWKS,
|
|
88
|
-
*
|
|
89
|
-
* device
|
|
216
|
+
* An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, authorization (PKCE required or not and its
|
|
217
|
+
* allowed methods, `state`, `nonce`, `prompt`, `max_age`, `acr_values`, `response_mode` query or web_message, RFC 9207
|
|
218
|
+
* `iss`), token (client credentials, authorization code with ID tokens, refresh, token exchange, password, device code,
|
|
219
|
+
* personal access token) with the client's exact authentication method, introspection, revocation, UserInfo, device
|
|
220
|
+
* authorization, end session, back-channel and front-channel logout delivery, tokens signed RS256 or HS* with the
|
|
221
|
+
* client secret, and JWE (RSA-OAEP, RSA-OAEP-256) for clients that registered an encryption key.
|
|
90
222
|
*/
|
|
91
223
|
declare class FakeAuthio {
|
|
92
224
|
/** Every request received, in order. */
|
|
93
225
|
readonly requests: FakeAuthioRecordedRequest[];
|
|
94
226
|
/** Answers the next requests to an endpoint with these errors, in order, before answering normally. */
|
|
95
|
-
readonly failures: Map<
|
|
227
|
+
readonly failures: Map<Endpoint, FakeAuthioError[]>;
|
|
228
|
+
/** Every back-channel logout token posted, in order. */
|
|
229
|
+
readonly backchannelDeliveries: FakeAuthioBackchannelDelivery[];
|
|
230
|
+
/** Every front-channel logout page loaded, in order. */
|
|
231
|
+
readonly frontchannelDeliveries: FakeAuthioFrontchannelDelivery[];
|
|
96
232
|
/** What successive device-code polls answer; the last value repeats. Defaults to `["approved"]`. */
|
|
97
233
|
deviceOutcomes: FakeAuthioDeviceOutcome[];
|
|
98
234
|
/** Overrides the discovery document's issuer, to test the mismatch check. */
|
|
99
235
|
discoveryIssuer: string | undefined;
|
|
100
|
-
/** Answers UserInfo as `application/jwt`, signed by the realm key. */
|
|
236
|
+
/** Answers UserInfo as `application/jwt`, signed by the realm key (and encrypted for a client with a key). */
|
|
101
237
|
userInfoAsJwt: boolean;
|
|
238
|
+
/** Leaves `iss` out of authorization responses, to test the RFC 9207 check. */
|
|
239
|
+
omitAuthorizationIssuer: boolean;
|
|
102
240
|
/** Answers connected-account exchanges. Defaults to granting a token for the provider. */
|
|
103
241
|
connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;
|
|
242
|
+
/** The person the authorization endpoint signs in when the request names none with `login_hint`. Defaults to the first user. */
|
|
243
|
+
signInAs: string | undefined;
|
|
104
244
|
private readonly clients;
|
|
105
245
|
private readonly users;
|
|
246
|
+
private readonly personalAccessTokens;
|
|
106
247
|
private readonly codes;
|
|
107
248
|
private readonly refreshTokens;
|
|
108
249
|
private readonly issued;
|
|
109
250
|
private readonly devicePolls;
|
|
110
251
|
private readonly lifetime;
|
|
252
|
+
private readonly clock;
|
|
253
|
+
private session;
|
|
111
254
|
private server;
|
|
112
255
|
private signingKey;
|
|
256
|
+
private verificationKey;
|
|
113
257
|
private untrustedKey;
|
|
114
258
|
private publicJwk;
|
|
115
259
|
private baseUrl;
|
|
@@ -128,10 +272,20 @@ declare class FakeAuthio {
|
|
|
128
272
|
get jwks(): {
|
|
129
273
|
keys: JWK[];
|
|
130
274
|
};
|
|
275
|
+
/** The session the authorization endpoint keeps (one browser), or `undefined` when nobody is signed in. */
|
|
276
|
+
get currentSession(): {
|
|
277
|
+
sub: string;
|
|
278
|
+
sid: string;
|
|
279
|
+
authTime: number;
|
|
280
|
+
} | undefined;
|
|
131
281
|
/** Registers a client. */
|
|
132
282
|
addClient(client: FakeAuthioClient): void;
|
|
133
283
|
/** Registers a person. */
|
|
134
284
|
addUser(user: FakeAuthioUser): void;
|
|
285
|
+
/** Registers a personal access token. */
|
|
286
|
+
addPersonalAccessToken(token: FakeAuthioPersonalAccessToken): void;
|
|
287
|
+
/** Ends the signed-in session without notifying anyone, as if it expired. */
|
|
288
|
+
endSession(): void;
|
|
135
289
|
/**
|
|
136
290
|
* Registers an authorization code for a person, as the authorization endpoint would after sign-in.
|
|
137
291
|
*/
|
|
@@ -142,13 +296,58 @@ declare class FakeAuthio {
|
|
|
142
296
|
scope?: string;
|
|
143
297
|
codeChallengeVerifier?: string;
|
|
144
298
|
resource?: string;
|
|
299
|
+
nonce?: string;
|
|
145
300
|
}): string;
|
|
301
|
+
/**
|
|
302
|
+
* Follows an authorization URL as a browser would, signing in `signInAs` (or the `login_hint`), and returns what
|
|
303
|
+
* Authio sent back: the callback URL for `response_mode=query`, the posted message's parameters for `web_message`.
|
|
304
|
+
*/
|
|
305
|
+
authorize(authorizationUrl: string): Promise<FakeAuthioAuthorizationOutcome>;
|
|
146
306
|
/**
|
|
147
307
|
* Mints an access token signed by the realm key, recorded so introspection and revocation know it.
|
|
148
308
|
*/
|
|
149
309
|
issueAccessToken(options?: FakeAuthioTokenOptions): Promise<string>;
|
|
150
|
-
/**
|
|
310
|
+
/**
|
|
311
|
+
* Mints a back-channel logout token for a client, signed by the realm key. `overrides` replaces claims (`undefined`
|
|
312
|
+
* removes one) and `type` the header `typ`, to build invalid ones in tests.
|
|
313
|
+
*/
|
|
314
|
+
createLogoutToken(options: {
|
|
315
|
+
clientId: string;
|
|
316
|
+
sub?: string;
|
|
317
|
+
sid?: string;
|
|
318
|
+
type?: string;
|
|
319
|
+
overrides?: Record<string, unknown>;
|
|
320
|
+
}): Promise<string>;
|
|
321
|
+
/**
|
|
322
|
+
* Posts a back-channel logout token to the client's `backchannelLogoutUri`, as Authio does when a session ends.
|
|
323
|
+
*
|
|
324
|
+
* @returns The HTTP status the client answered, or 0 when it could not be reached.
|
|
325
|
+
*/
|
|
326
|
+
deliverBackchannelLogout(clientId: string, options?: {
|
|
327
|
+
sub?: string;
|
|
328
|
+
sid?: string;
|
|
329
|
+
}): Promise<number>;
|
|
330
|
+
/**
|
|
331
|
+
* The front-channel logout URL of a client for a session: its `frontchannelLogoutUri`, with `iss` and `sid` when the
|
|
332
|
+
* client requires the session.
|
|
333
|
+
*/
|
|
334
|
+
frontchannelLogoutUrl(clientId: string, sid: string): string;
|
|
335
|
+
/**
|
|
336
|
+
* Loads the client's front-channel logout page, as the browser does in an iframe when Authio ends a session.
|
|
337
|
+
*
|
|
338
|
+
* @returns The HTTP status the client answered, or 0 when it could not be reached.
|
|
339
|
+
*/
|
|
340
|
+
deliverFrontchannelLogout(clientId: string, options: {
|
|
341
|
+
sid: string;
|
|
342
|
+
headers?: Record<string, string>;
|
|
343
|
+
}): Promise<number>;
|
|
344
|
+
/** Marks a token revoked, as Authio would after a sign-out: an access token, or a refresh token, which is then forgotten. */
|
|
151
345
|
revokeToken(token: string): void;
|
|
346
|
+
/** Revokes every refresh token of a person, or of one Authio session (`sid`), as Authio does when a session ends. */
|
|
347
|
+
revokeRefreshTokens(options: {
|
|
348
|
+
sub?: string;
|
|
349
|
+
sid?: string;
|
|
350
|
+
}): void;
|
|
152
351
|
/** Forgets the recorded requests. */
|
|
153
352
|
clearRequests(): void;
|
|
154
353
|
/** The recorded requests to one endpoint path suffix, such as `/token`. */
|
|
@@ -158,6 +357,8 @@ declare class FakeAuthio {
|
|
|
158
357
|
private listen;
|
|
159
358
|
private handle;
|
|
160
359
|
private discovery;
|
|
360
|
+
private authorizeEndpoint;
|
|
361
|
+
private endSessionEndpoint;
|
|
161
362
|
private authenticate;
|
|
162
363
|
private token;
|
|
163
364
|
private tokenAnswer;
|
|
@@ -165,6 +366,9 @@ declare class FakeAuthio {
|
|
|
165
366
|
private revoke;
|
|
166
367
|
private device;
|
|
167
368
|
private userInfo;
|
|
369
|
+
private nowSeconds;
|
|
370
|
+
private sign;
|
|
371
|
+
private verificationKeyFor;
|
|
168
372
|
private requireUser;
|
|
169
373
|
}
|
|
170
374
|
|
|
@@ -212,4 +416,4 @@ declare function createWebhookDelivery(type: string, data: unknown, secret: stri
|
|
|
212
416
|
sendEventIdHeader?: boolean;
|
|
213
417
|
}): Promise<FakeWebhookDelivery>;
|
|
214
418
|
|
|
215
|
-
export { FakeAuthio, type FakeAuthioClient, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioOptions, type FakeAuthioRecordedRequest, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };
|
|
419
|
+
export { FakeAuthio, type FakeAuthioAuthorizationOutcome, type FakeAuthioBackchannelDelivery, type FakeAuthioClient, type FakeAuthioClientEncryption, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioFrontchannelDelivery, type FakeAuthioOptions, type FakeAuthioPersonalAccessToken, type FakeAuthioRecordedRequest, type FakeAuthioSigningAlgorithm, type FakeAuthioTokenEndpointAuthMethod, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,20 +2,86 @@ import { JWK } from 'jose';
|
|
|
2
2
|
import { AuthioClock } from '@hyper.authio/client';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* How the fake encrypts what it issues to a client, as Authio does once the client registered an encryption key.
|
|
6
|
+
*/
|
|
7
|
+
interface FakeAuthioClientEncryption {
|
|
8
|
+
/** The client's public encryption key (RSA). */
|
|
9
|
+
key: JWK;
|
|
10
|
+
/** Defaults to `RSA-OAEP-256`. */
|
|
11
|
+
algorithm?: "RSA-OAEP" | "RSA-OAEP-256";
|
|
12
|
+
/** Defaults to `A256CBC-HS512`. */
|
|
13
|
+
encryptionMethod?: "A128CBC-HS256" | "A192CBC-HS384" | "A256CBC-HS512";
|
|
14
|
+
/** Encrypts the client's access tokens (nested JWT). */
|
|
15
|
+
accessTokens?: boolean;
|
|
16
|
+
/** Encrypts the client's ID tokens. Defaults to `true`. */
|
|
17
|
+
idTokens?: boolean;
|
|
18
|
+
/** Encrypts UserInfo answered as a JWT. Defaults to `true`. */
|
|
19
|
+
userInfo?: boolean;
|
|
20
|
+
/** Encrypts back-channel logout tokens. */
|
|
21
|
+
logoutTokens?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* How a client authenticates to the token, introspection, revocation and device endpoints, as registered in Authio.
|
|
25
|
+
*/
|
|
26
|
+
type FakeAuthioTokenEndpointAuthMethod = "client_secret_basic" | "client_secret_post" | "private_key_jwt" | "none";
|
|
27
|
+
/**
|
|
28
|
+
* The algorithm Authio signs every token of a client with: the realm's RSA key, or the client secret (HS*).
|
|
29
|
+
*/
|
|
30
|
+
type FakeAuthioSigningAlgorithm = "RS256" | "HS256" | "HS384" | "HS512";
|
|
31
|
+
/**
|
|
32
|
+
* A client registered in the fake, configured as a client is in Authio's console. What the client requires is
|
|
33
|
+
* enforced as Authio enforces it: a request that does not match is refused with an error naming the setting, and
|
|
34
|
+
* what the client does not require is accepted (PKCE sent voluntarily, a secret sent by a public client).
|
|
6
35
|
*/
|
|
7
36
|
interface FakeAuthioClient {
|
|
8
37
|
clientId: string;
|
|
9
|
-
/** For `client_secret_basic` and `client_secret_post
|
|
38
|
+
/** For `client_secret_basic` and `client_secret_post`, and the key of HS* signatures. */
|
|
10
39
|
clientSecret?: string;
|
|
11
40
|
/** The public JWK `private_key_jwt` assertions are verified with. */
|
|
12
41
|
publicKey?: JWK;
|
|
42
|
+
/**
|
|
43
|
+
* How the client must authenticate; another method is refused with `invalid_client`, except a secret sent by a
|
|
44
|
+
* `none` client, which is ignored. Defaults to `client_secret_basic` with a `clientSecret`, `private_key_jwt` with
|
|
45
|
+
* only a `publicKey`, and `none` with neither.
|
|
46
|
+
*/
|
|
47
|
+
tokenEndpointAuthMethod?: FakeAuthioTokenEndpointAuthMethod;
|
|
48
|
+
/**
|
|
49
|
+
* Refuses an authorization request without `code_challenge` (Authio's "PKCE" switch). Defaults to `true`, as Authio
|
|
50
|
+
* creates clients; set `false` for a client with PKCE off.
|
|
51
|
+
*/
|
|
52
|
+
requirePkce?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The PKCE methods accepted, required or not: a `code_challenge` with another method is refused. Defaults to
|
|
55
|
+
* `["S256"]`, as Authio creates clients.
|
|
56
|
+
*/
|
|
57
|
+
pkceMethods?: ("S256" | "plain")[];
|
|
58
|
+
/**
|
|
59
|
+
* The algorithm the client's ID tokens, signed UserInfo and logout tokens are signed with. Defaults to `RS256`. HS*
|
|
60
|
+
* needs a `clientSecret` of at least 32, 48 or 64 bytes (RFC 7518 §3.2), as Authio requires.
|
|
61
|
+
*/
|
|
62
|
+
signingAlgorithm?: FakeAuthioSigningAlgorithm;
|
|
63
|
+
/** The algorithm the client's access tokens are signed with, Authio's second setting. Defaults to `RS256`. */
|
|
64
|
+
accessTokenSigningAlgorithm?: FakeAuthioSigningAlgorithm;
|
|
65
|
+
/** Issues a new ID token with every refresh. Defaults to `false`. */
|
|
66
|
+
issueIdTokenOnRefresh?: boolean;
|
|
13
67
|
/** Scopes granted when a request names none. */
|
|
14
68
|
defaultScopes?: string[];
|
|
15
69
|
/** Extra claims put into every access token issued to the client. */
|
|
16
70
|
claims?: Record<string, unknown>;
|
|
17
71
|
/** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */
|
|
18
72
|
introspectionClients?: string[];
|
|
73
|
+
/** The redirect URIs the authorization endpoint accepts. Any when absent. */
|
|
74
|
+
redirectUris?: string[];
|
|
75
|
+
/** The post-logout redirect URIs the end-session endpoint accepts. Any when absent. */
|
|
76
|
+
postLogoutRedirectUris?: string[];
|
|
77
|
+
/** Where back-channel logout tokens are posted when a session of the client ends. */
|
|
78
|
+
backchannelLogoutUri?: string;
|
|
79
|
+
/** The page loaded (here: fetched) when a session of the client ends (front-channel logout). */
|
|
80
|
+
frontchannelLogoutUri?: string;
|
|
81
|
+
/** Adds `iss` and `sid` to the front-channel logout URI. Defaults to `false`. */
|
|
82
|
+
frontchannelLogoutSessionRequired?: boolean;
|
|
83
|
+
/** Encrypts what is issued to the client. */
|
|
84
|
+
encryption?: FakeAuthioClientEncryption;
|
|
19
85
|
}
|
|
20
86
|
/**
|
|
21
87
|
* A person the fake knows, for the password grant, authorization codes and UserInfo.
|
|
@@ -28,6 +94,23 @@ interface FakeAuthioUser {
|
|
|
28
94
|
claims?: Record<string, unknown>;
|
|
29
95
|
/** What UserInfo answers besides `sub`. */
|
|
30
96
|
userInfo?: Record<string, unknown>;
|
|
97
|
+
/** The sign-in's methods. Defaults to `["pwd"]`. */
|
|
98
|
+
amr?: string[];
|
|
99
|
+
/** The sign-in's level. Defaults to `1`, or the `acr_values` asked for. */
|
|
100
|
+
acr?: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A personal access token the fake accepts with the `personal_access_token` grant.
|
|
104
|
+
*/
|
|
105
|
+
interface FakeAuthioPersonalAccessToken {
|
|
106
|
+
/** The `pat_…` value. */
|
|
107
|
+
token: string;
|
|
108
|
+
/** The credential's id, the token's `sub`. */
|
|
109
|
+
sub: string;
|
|
110
|
+
/** The consumer's client, for a consumer's token; the `authio` client of an account otherwise. */
|
|
111
|
+
clientId?: string;
|
|
112
|
+
/** Claims added to the access token. */
|
|
113
|
+
claims?: Record<string, unknown>;
|
|
31
114
|
}
|
|
32
115
|
/**
|
|
33
116
|
* An error the fake answers a request with.
|
|
@@ -45,9 +128,40 @@ interface FakeAuthioRecordedRequest {
|
|
|
45
128
|
path: string;
|
|
46
129
|
headers: Record<string, string>;
|
|
47
130
|
form: Record<string, string>;
|
|
131
|
+
/** The query parameters. */
|
|
132
|
+
query: Record<string, string>;
|
|
48
133
|
/** The client the request authenticated as, when it did. */
|
|
49
134
|
clientId?: string;
|
|
50
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* A back-channel logout token the fake posted to a client.
|
|
138
|
+
*/
|
|
139
|
+
interface FakeAuthioBackchannelDelivery {
|
|
140
|
+
clientId: string;
|
|
141
|
+
uri: string;
|
|
142
|
+
logoutToken: string;
|
|
143
|
+
/** The HTTP status the client answered, or 0 when it could not be reached. */
|
|
144
|
+
status: number;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A front-channel logout page the fake loaded for a client.
|
|
148
|
+
*/
|
|
149
|
+
interface FakeAuthioFrontchannelDelivery {
|
|
150
|
+
clientId: string;
|
|
151
|
+
/** The URL loaded, with `iss` and `sid` when the client requires the session. */
|
|
152
|
+
url: string;
|
|
153
|
+
/** The HTTP status the client answered, or 0 when it could not be reached. */
|
|
154
|
+
status: number;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The parameters an authorization ended with, as the fake sent them back.
|
|
158
|
+
*/
|
|
159
|
+
interface FakeAuthioAuthorizationOutcome {
|
|
160
|
+
/** `code`, `state` and `iss`, or `error`, `error_description`, `state` and `iss`. */
|
|
161
|
+
parameters: Record<string, string>;
|
|
162
|
+
/** The redirect URI with the parameters, for `response_mode=query`. */
|
|
163
|
+
callbackUrl: string | undefined;
|
|
164
|
+
}
|
|
51
165
|
/**
|
|
52
166
|
* What the device flow answers to successive polls.
|
|
53
167
|
*/
|
|
@@ -62,6 +176,14 @@ interface FakeAuthioOptions {
|
|
|
62
176
|
accessTokenLifetime?: number;
|
|
63
177
|
clients?: FakeAuthioClient[];
|
|
64
178
|
users?: FakeAuthioUser[];
|
|
179
|
+
personalAccessTokens?: FakeAuthioPersonalAccessToken[];
|
|
180
|
+
/**
|
|
181
|
+
* The clock tokens are issued and checked with (milliseconds since the epoch), such as the `ManualClock` the
|
|
182
|
+
* library under test uses. Defaults to the system clock.
|
|
183
|
+
*/
|
|
184
|
+
clock?: {
|
|
185
|
+
now(): number;
|
|
186
|
+
};
|
|
65
187
|
}
|
|
66
188
|
/**
|
|
67
189
|
* Options of a token minted directly.
|
|
@@ -82,34 +204,56 @@ interface FakeAuthioTokenOptions {
|
|
|
82
204
|
issuer?: string;
|
|
83
205
|
/** Signs with another key, so the signature does not verify. */
|
|
84
206
|
untrusted?: boolean;
|
|
207
|
+
/** Encrypts the token (nested JWT) to this public key, as Authio does for a client with an encryption key. */
|
|
208
|
+
encryptTo?: {
|
|
209
|
+
key: JWK;
|
|
210
|
+
algorithm?: "RSA-OAEP" | "RSA-OAEP-256";
|
|
211
|
+
encryptionMethod?: string;
|
|
212
|
+
};
|
|
85
213
|
}
|
|
214
|
+
type Endpoint = "token" | "introspect" | "revoke" | "userinfo" | "device" | "discovery" | "authorize" | "logout";
|
|
86
215
|
/**
|
|
87
|
-
* An in-memory Authio realm served over HTTP on loopback: discovery, JWKS,
|
|
88
|
-
*
|
|
89
|
-
* device
|
|
216
|
+
* An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, authorization (PKCE required or not and its
|
|
217
|
+
* allowed methods, `state`, `nonce`, `prompt`, `max_age`, `acr_values`, `response_mode` query or web_message, RFC 9207
|
|
218
|
+
* `iss`), token (client credentials, authorization code with ID tokens, refresh, token exchange, password, device code,
|
|
219
|
+
* personal access token) with the client's exact authentication method, introspection, revocation, UserInfo, device
|
|
220
|
+
* authorization, end session, back-channel and front-channel logout delivery, tokens signed RS256 or HS* with the
|
|
221
|
+
* client secret, and JWE (RSA-OAEP, RSA-OAEP-256) for clients that registered an encryption key.
|
|
90
222
|
*/
|
|
91
223
|
declare class FakeAuthio {
|
|
92
224
|
/** Every request received, in order. */
|
|
93
225
|
readonly requests: FakeAuthioRecordedRequest[];
|
|
94
226
|
/** Answers the next requests to an endpoint with these errors, in order, before answering normally. */
|
|
95
|
-
readonly failures: Map<
|
|
227
|
+
readonly failures: Map<Endpoint, FakeAuthioError[]>;
|
|
228
|
+
/** Every back-channel logout token posted, in order. */
|
|
229
|
+
readonly backchannelDeliveries: FakeAuthioBackchannelDelivery[];
|
|
230
|
+
/** Every front-channel logout page loaded, in order. */
|
|
231
|
+
readonly frontchannelDeliveries: FakeAuthioFrontchannelDelivery[];
|
|
96
232
|
/** What successive device-code polls answer; the last value repeats. Defaults to `["approved"]`. */
|
|
97
233
|
deviceOutcomes: FakeAuthioDeviceOutcome[];
|
|
98
234
|
/** Overrides the discovery document's issuer, to test the mismatch check. */
|
|
99
235
|
discoveryIssuer: string | undefined;
|
|
100
|
-
/** Answers UserInfo as `application/jwt`, signed by the realm key. */
|
|
236
|
+
/** Answers UserInfo as `application/jwt`, signed by the realm key (and encrypted for a client with a key). */
|
|
101
237
|
userInfoAsJwt: boolean;
|
|
238
|
+
/** Leaves `iss` out of authorization responses, to test the RFC 9207 check. */
|
|
239
|
+
omitAuthorizationIssuer: boolean;
|
|
102
240
|
/** Answers connected-account exchanges. Defaults to granting a token for the provider. */
|
|
103
241
|
connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;
|
|
242
|
+
/** The person the authorization endpoint signs in when the request names none with `login_hint`. Defaults to the first user. */
|
|
243
|
+
signInAs: string | undefined;
|
|
104
244
|
private readonly clients;
|
|
105
245
|
private readonly users;
|
|
246
|
+
private readonly personalAccessTokens;
|
|
106
247
|
private readonly codes;
|
|
107
248
|
private readonly refreshTokens;
|
|
108
249
|
private readonly issued;
|
|
109
250
|
private readonly devicePolls;
|
|
110
251
|
private readonly lifetime;
|
|
252
|
+
private readonly clock;
|
|
253
|
+
private session;
|
|
111
254
|
private server;
|
|
112
255
|
private signingKey;
|
|
256
|
+
private verificationKey;
|
|
113
257
|
private untrustedKey;
|
|
114
258
|
private publicJwk;
|
|
115
259
|
private baseUrl;
|
|
@@ -128,10 +272,20 @@ declare class FakeAuthio {
|
|
|
128
272
|
get jwks(): {
|
|
129
273
|
keys: JWK[];
|
|
130
274
|
};
|
|
275
|
+
/** The session the authorization endpoint keeps (one browser), or `undefined` when nobody is signed in. */
|
|
276
|
+
get currentSession(): {
|
|
277
|
+
sub: string;
|
|
278
|
+
sid: string;
|
|
279
|
+
authTime: number;
|
|
280
|
+
} | undefined;
|
|
131
281
|
/** Registers a client. */
|
|
132
282
|
addClient(client: FakeAuthioClient): void;
|
|
133
283
|
/** Registers a person. */
|
|
134
284
|
addUser(user: FakeAuthioUser): void;
|
|
285
|
+
/** Registers a personal access token. */
|
|
286
|
+
addPersonalAccessToken(token: FakeAuthioPersonalAccessToken): void;
|
|
287
|
+
/** Ends the signed-in session without notifying anyone, as if it expired. */
|
|
288
|
+
endSession(): void;
|
|
135
289
|
/**
|
|
136
290
|
* Registers an authorization code for a person, as the authorization endpoint would after sign-in.
|
|
137
291
|
*/
|
|
@@ -142,13 +296,58 @@ declare class FakeAuthio {
|
|
|
142
296
|
scope?: string;
|
|
143
297
|
codeChallengeVerifier?: string;
|
|
144
298
|
resource?: string;
|
|
299
|
+
nonce?: string;
|
|
145
300
|
}): string;
|
|
301
|
+
/**
|
|
302
|
+
* Follows an authorization URL as a browser would, signing in `signInAs` (or the `login_hint`), and returns what
|
|
303
|
+
* Authio sent back: the callback URL for `response_mode=query`, the posted message's parameters for `web_message`.
|
|
304
|
+
*/
|
|
305
|
+
authorize(authorizationUrl: string): Promise<FakeAuthioAuthorizationOutcome>;
|
|
146
306
|
/**
|
|
147
307
|
* Mints an access token signed by the realm key, recorded so introspection and revocation know it.
|
|
148
308
|
*/
|
|
149
309
|
issueAccessToken(options?: FakeAuthioTokenOptions): Promise<string>;
|
|
150
|
-
/**
|
|
310
|
+
/**
|
|
311
|
+
* Mints a back-channel logout token for a client, signed by the realm key. `overrides` replaces claims (`undefined`
|
|
312
|
+
* removes one) and `type` the header `typ`, to build invalid ones in tests.
|
|
313
|
+
*/
|
|
314
|
+
createLogoutToken(options: {
|
|
315
|
+
clientId: string;
|
|
316
|
+
sub?: string;
|
|
317
|
+
sid?: string;
|
|
318
|
+
type?: string;
|
|
319
|
+
overrides?: Record<string, unknown>;
|
|
320
|
+
}): Promise<string>;
|
|
321
|
+
/**
|
|
322
|
+
* Posts a back-channel logout token to the client's `backchannelLogoutUri`, as Authio does when a session ends.
|
|
323
|
+
*
|
|
324
|
+
* @returns The HTTP status the client answered, or 0 when it could not be reached.
|
|
325
|
+
*/
|
|
326
|
+
deliverBackchannelLogout(clientId: string, options?: {
|
|
327
|
+
sub?: string;
|
|
328
|
+
sid?: string;
|
|
329
|
+
}): Promise<number>;
|
|
330
|
+
/**
|
|
331
|
+
* The front-channel logout URL of a client for a session: its `frontchannelLogoutUri`, with `iss` and `sid` when the
|
|
332
|
+
* client requires the session.
|
|
333
|
+
*/
|
|
334
|
+
frontchannelLogoutUrl(clientId: string, sid: string): string;
|
|
335
|
+
/**
|
|
336
|
+
* Loads the client's front-channel logout page, as the browser does in an iframe when Authio ends a session.
|
|
337
|
+
*
|
|
338
|
+
* @returns The HTTP status the client answered, or 0 when it could not be reached.
|
|
339
|
+
*/
|
|
340
|
+
deliverFrontchannelLogout(clientId: string, options: {
|
|
341
|
+
sid: string;
|
|
342
|
+
headers?: Record<string, string>;
|
|
343
|
+
}): Promise<number>;
|
|
344
|
+
/** Marks a token revoked, as Authio would after a sign-out: an access token, or a refresh token, which is then forgotten. */
|
|
151
345
|
revokeToken(token: string): void;
|
|
346
|
+
/** Revokes every refresh token of a person, or of one Authio session (`sid`), as Authio does when a session ends. */
|
|
347
|
+
revokeRefreshTokens(options: {
|
|
348
|
+
sub?: string;
|
|
349
|
+
sid?: string;
|
|
350
|
+
}): void;
|
|
152
351
|
/** Forgets the recorded requests. */
|
|
153
352
|
clearRequests(): void;
|
|
154
353
|
/** The recorded requests to one endpoint path suffix, such as `/token`. */
|
|
@@ -158,6 +357,8 @@ declare class FakeAuthio {
|
|
|
158
357
|
private listen;
|
|
159
358
|
private handle;
|
|
160
359
|
private discovery;
|
|
360
|
+
private authorizeEndpoint;
|
|
361
|
+
private endSessionEndpoint;
|
|
161
362
|
private authenticate;
|
|
162
363
|
private token;
|
|
163
364
|
private tokenAnswer;
|
|
@@ -165,6 +366,9 @@ declare class FakeAuthio {
|
|
|
165
366
|
private revoke;
|
|
166
367
|
private device;
|
|
167
368
|
private userInfo;
|
|
369
|
+
private nowSeconds;
|
|
370
|
+
private sign;
|
|
371
|
+
private verificationKeyFor;
|
|
168
372
|
private requireUser;
|
|
169
373
|
}
|
|
170
374
|
|
|
@@ -212,4 +416,4 @@ declare function createWebhookDelivery(type: string, data: unknown, secret: stri
|
|
|
212
416
|
sendEventIdHeader?: boolean;
|
|
213
417
|
}): Promise<FakeWebhookDelivery>;
|
|
214
418
|
|
|
215
|
-
export { FakeAuthio, type FakeAuthioClient, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioOptions, type FakeAuthioRecordedRequest, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };
|
|
419
|
+
export { FakeAuthio, type FakeAuthioAuthorizationOutcome, type FakeAuthioBackchannelDelivery, type FakeAuthioClient, type FakeAuthioClientEncryption, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioFrontchannelDelivery, type FakeAuthioOptions, type FakeAuthioPersonalAccessToken, type FakeAuthioRecordedRequest, type FakeAuthioSigningAlgorithm, type FakeAuthioTokenEndpointAuthMethod, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };
|