@hyper.authio/testing 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,215 @@
1
+ import { JWK } from 'jose';
2
+ import { AuthioClock } from '@hyper.authio/client';
3
+
4
+ /**
5
+ * A client registered in the fake.
6
+ */
7
+ interface FakeAuthioClient {
8
+ clientId: string;
9
+ /** For `client_secret_basic` and `client_secret_post`. */
10
+ clientSecret?: string;
11
+ /** The public JWK `private_key_jwt` assertions are verified with. */
12
+ publicKey?: JWK;
13
+ /** Scopes granted when a request names none. */
14
+ defaultScopes?: string[];
15
+ /** Extra claims put into every access token issued to the client. */
16
+ claims?: Record<string, unknown>;
17
+ /** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */
18
+ introspectionClients?: string[];
19
+ }
20
+ /**
21
+ * A person the fake knows, for the password grant, authorization codes and UserInfo.
22
+ */
23
+ interface FakeAuthioUser {
24
+ sub: string;
25
+ username: string;
26
+ password?: string;
27
+ /** Claims put into the person's access tokens: `*_resource_access`, `org_id`, mapper claims… */
28
+ claims?: Record<string, unknown>;
29
+ /** What UserInfo answers besides `sub`. */
30
+ userInfo?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * An error the fake answers a request with.
34
+ */
35
+ interface FakeAuthioError {
36
+ status: number;
37
+ body?: Record<string, unknown>;
38
+ headers?: Record<string, string>;
39
+ }
40
+ /**
41
+ * A request the fake received.
42
+ */
43
+ interface FakeAuthioRecordedRequest {
44
+ method: string;
45
+ path: string;
46
+ headers: Record<string, string>;
47
+ form: Record<string, string>;
48
+ /** The client the request authenticated as, when it did. */
49
+ clientId?: string;
50
+ }
51
+ /**
52
+ * What the device flow answers to successive polls.
53
+ */
54
+ type FakeAuthioDeviceOutcome = "pending" | "slow_down" | "approved" | "denied" | "expired";
55
+ /**
56
+ * Options of the fake.
57
+ */
58
+ interface FakeAuthioOptions {
59
+ /** The realm. Defaults to `fake`. */
60
+ realm?: string;
61
+ /** Seconds tokens live. Defaults to 300. */
62
+ accessTokenLifetime?: number;
63
+ clients?: FakeAuthioClient[];
64
+ users?: FakeAuthioUser[];
65
+ }
66
+ /**
67
+ * Options of a token minted directly.
68
+ */
69
+ interface FakeAuthioTokenOptions {
70
+ sub?: string;
71
+ /** One or several audiences. Defaults to the client id. */
72
+ audience?: string | string[];
73
+ clientId?: string;
74
+ scope?: string;
75
+ /** Seconds. Negative values mint an expired token. */
76
+ expiresIn?: number;
77
+ /** The `typ` claim. Defaults to `Bearer`. */
78
+ type?: string;
79
+ /** Claims added to the payload. */
80
+ claims?: Record<string, unknown>;
81
+ /** Signs with another issuer. */
82
+ issuer?: string;
83
+ /** Signs with another key, so the signature does not verify. */
84
+ untrusted?: boolean;
85
+ }
86
+ /**
87
+ * An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, token (client credentials,
88
+ * authorization code, refresh, token exchange, password, device code), introspection, revocation, UserInfo and
89
+ * device authorization.
90
+ */
91
+ declare class FakeAuthio {
92
+ /** Every request received, in order. */
93
+ readonly requests: FakeAuthioRecordedRequest[];
94
+ /** Answers the next requests to an endpoint with these errors, in order, before answering normally. */
95
+ readonly failures: Map<"token" | "introspect" | "revoke" | "userinfo" | "device" | "discovery", FakeAuthioError[]>;
96
+ /** What successive device-code polls answer; the last value repeats. Defaults to `["approved"]`. */
97
+ deviceOutcomes: FakeAuthioDeviceOutcome[];
98
+ /** Overrides the discovery document's issuer, to test the mismatch check. */
99
+ discoveryIssuer: string | undefined;
100
+ /** Answers UserInfo as `application/jwt`, signed by the realm key. */
101
+ userInfoAsJwt: boolean;
102
+ /** Answers connected-account exchanges. Defaults to granting a token for the provider. */
103
+ connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;
104
+ private readonly clients;
105
+ private readonly users;
106
+ private readonly codes;
107
+ private readonly refreshTokens;
108
+ private readonly issued;
109
+ private readonly devicePolls;
110
+ private readonly lifetime;
111
+ private server;
112
+ private signingKey;
113
+ private untrustedKey;
114
+ private publicJwk;
115
+ private baseUrl;
116
+ readonly realm: string;
117
+ readonly keyId = "fake-key-1";
118
+ private constructor();
119
+ /**
120
+ * Starts the fake on a random loopback port.
121
+ */
122
+ static start(options?: FakeAuthioOptions): Promise<FakeAuthio>;
123
+ /** `http://127.0.0.1:{port}`. */
124
+ get authority(): string;
125
+ /** `{authority}/realms/{realm}`. */
126
+ get issuer(): string;
127
+ /** The realm's public signing key. */
128
+ get jwks(): {
129
+ keys: JWK[];
130
+ };
131
+ /** Registers a client. */
132
+ addClient(client: FakeAuthioClient): void;
133
+ /** Registers a person. */
134
+ addUser(user: FakeAuthioUser): void;
135
+ /**
136
+ * Registers an authorization code for a person, as the authorization endpoint would after sign-in.
137
+ */
138
+ createAuthorizationCode(options: {
139
+ clientId: string;
140
+ username: string;
141
+ redirectUri: string;
142
+ scope?: string;
143
+ codeChallengeVerifier?: string;
144
+ resource?: string;
145
+ }): string;
146
+ /**
147
+ * Mints an access token signed by the realm key, recorded so introspection and revocation know it.
148
+ */
149
+ issueAccessToken(options?: FakeAuthioTokenOptions): Promise<string>;
150
+ /** Marks a token revoked, as Authio would after a sign-out. */
151
+ revokeToken(token: string): void;
152
+ /** Forgets the recorded requests. */
153
+ clearRequests(): void;
154
+ /** The recorded requests to one endpoint path suffix, such as `/token`. */
155
+ requestsTo(suffix: string): FakeAuthioRecordedRequest[];
156
+ /** Stops the server. */
157
+ close(): Promise<void>;
158
+ private listen;
159
+ private handle;
160
+ private discovery;
161
+ private authenticate;
162
+ private token;
163
+ private tokenAnswer;
164
+ private introspect;
165
+ private revoke;
166
+ private device;
167
+ private userInfo;
168
+ private requireUser;
169
+ }
170
+
171
+ /**
172
+ * A clock that moves only when told to. `sleep` returns at once and moves the clock forward by the time asked, so
173
+ * device polling and cache expiry run instantly and deterministically.
174
+ */
175
+ declare class ManualClock implements AuthioClock {
176
+ /** Every `sleep` asked for, in milliseconds. */
177
+ readonly sleeps: number[];
178
+ private time;
179
+ /**
180
+ * @param start Milliseconds since the epoch. Defaults to the current time.
181
+ */
182
+ constructor(start?: number);
183
+ now(): number;
184
+ sleep(ms: number, signal?: AbortSignal): Promise<void>;
185
+ /** Moves the clock forward. */
186
+ advance(ms: number): void;
187
+ /** Sets the clock. */
188
+ set(ms: number): void;
189
+ }
190
+
191
+ /**
192
+ * A webhook delivery as Authio would send it.
193
+ */
194
+ interface FakeWebhookDelivery {
195
+ readonly body: string;
196
+ readonly headers: Record<string, string>;
197
+ readonly event: Record<string, unknown>;
198
+ }
199
+ /**
200
+ * Builds a signed webhook delivery.
201
+ *
202
+ * @param type The event type.
203
+ * @param data The event data.
204
+ * @param secret The webhook secret.
205
+ * @param options `id`, `timestamp` (milliseconds) and extra event members.
206
+ */
207
+ declare function createWebhookDelivery(type: string, data: unknown, secret: string, options?: {
208
+ id?: string;
209
+ timestamp?: number;
210
+ realmId?: string;
211
+ clientId?: string;
212
+ sendEventIdHeader?: boolean;
213
+ }): Promise<FakeWebhookDelivery>;
214
+
215
+ export { FakeAuthio, type FakeAuthioClient, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioOptions, type FakeAuthioRecordedRequest, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };
@@ -0,0 +1,215 @@
1
+ import { JWK } from 'jose';
2
+ import { AuthioClock } from '@hyper.authio/client';
3
+
4
+ /**
5
+ * A client registered in the fake.
6
+ */
7
+ interface FakeAuthioClient {
8
+ clientId: string;
9
+ /** For `client_secret_basic` and `client_secret_post`. */
10
+ clientSecret?: string;
11
+ /** The public JWK `private_key_jwt` assertions are verified with. */
12
+ publicKey?: JWK;
13
+ /** Scopes granted when a request names none. */
14
+ defaultScopes?: string[];
15
+ /** Extra claims put into every access token issued to the client. */
16
+ claims?: Record<string, unknown>;
17
+ /** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */
18
+ introspectionClients?: string[];
19
+ }
20
+ /**
21
+ * A person the fake knows, for the password grant, authorization codes and UserInfo.
22
+ */
23
+ interface FakeAuthioUser {
24
+ sub: string;
25
+ username: string;
26
+ password?: string;
27
+ /** Claims put into the person's access tokens: `*_resource_access`, `org_id`, mapper claims… */
28
+ claims?: Record<string, unknown>;
29
+ /** What UserInfo answers besides `sub`. */
30
+ userInfo?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * An error the fake answers a request with.
34
+ */
35
+ interface FakeAuthioError {
36
+ status: number;
37
+ body?: Record<string, unknown>;
38
+ headers?: Record<string, string>;
39
+ }
40
+ /**
41
+ * A request the fake received.
42
+ */
43
+ interface FakeAuthioRecordedRequest {
44
+ method: string;
45
+ path: string;
46
+ headers: Record<string, string>;
47
+ form: Record<string, string>;
48
+ /** The client the request authenticated as, when it did. */
49
+ clientId?: string;
50
+ }
51
+ /**
52
+ * What the device flow answers to successive polls.
53
+ */
54
+ type FakeAuthioDeviceOutcome = "pending" | "slow_down" | "approved" | "denied" | "expired";
55
+ /**
56
+ * Options of the fake.
57
+ */
58
+ interface FakeAuthioOptions {
59
+ /** The realm. Defaults to `fake`. */
60
+ realm?: string;
61
+ /** Seconds tokens live. Defaults to 300. */
62
+ accessTokenLifetime?: number;
63
+ clients?: FakeAuthioClient[];
64
+ users?: FakeAuthioUser[];
65
+ }
66
+ /**
67
+ * Options of a token minted directly.
68
+ */
69
+ interface FakeAuthioTokenOptions {
70
+ sub?: string;
71
+ /** One or several audiences. Defaults to the client id. */
72
+ audience?: string | string[];
73
+ clientId?: string;
74
+ scope?: string;
75
+ /** Seconds. Negative values mint an expired token. */
76
+ expiresIn?: number;
77
+ /** The `typ` claim. Defaults to `Bearer`. */
78
+ type?: string;
79
+ /** Claims added to the payload. */
80
+ claims?: Record<string, unknown>;
81
+ /** Signs with another issuer. */
82
+ issuer?: string;
83
+ /** Signs with another key, so the signature does not verify. */
84
+ untrusted?: boolean;
85
+ }
86
+ /**
87
+ * An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, token (client credentials,
88
+ * authorization code, refresh, token exchange, password, device code), introspection, revocation, UserInfo and
89
+ * device authorization.
90
+ */
91
+ declare class FakeAuthio {
92
+ /** Every request received, in order. */
93
+ readonly requests: FakeAuthioRecordedRequest[];
94
+ /** Answers the next requests to an endpoint with these errors, in order, before answering normally. */
95
+ readonly failures: Map<"token" | "introspect" | "revoke" | "userinfo" | "device" | "discovery", FakeAuthioError[]>;
96
+ /** What successive device-code polls answer; the last value repeats. Defaults to `["approved"]`. */
97
+ deviceOutcomes: FakeAuthioDeviceOutcome[];
98
+ /** Overrides the discovery document's issuer, to test the mismatch check. */
99
+ discoveryIssuer: string | undefined;
100
+ /** Answers UserInfo as `application/jwt`, signed by the realm key. */
101
+ userInfoAsJwt: boolean;
102
+ /** Answers connected-account exchanges. Defaults to granting a token for the provider. */
103
+ connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;
104
+ private readonly clients;
105
+ private readonly users;
106
+ private readonly codes;
107
+ private readonly refreshTokens;
108
+ private readonly issued;
109
+ private readonly devicePolls;
110
+ private readonly lifetime;
111
+ private server;
112
+ private signingKey;
113
+ private untrustedKey;
114
+ private publicJwk;
115
+ private baseUrl;
116
+ readonly realm: string;
117
+ readonly keyId = "fake-key-1";
118
+ private constructor();
119
+ /**
120
+ * Starts the fake on a random loopback port.
121
+ */
122
+ static start(options?: FakeAuthioOptions): Promise<FakeAuthio>;
123
+ /** `http://127.0.0.1:{port}`. */
124
+ get authority(): string;
125
+ /** `{authority}/realms/{realm}`. */
126
+ get issuer(): string;
127
+ /** The realm's public signing key. */
128
+ get jwks(): {
129
+ keys: JWK[];
130
+ };
131
+ /** Registers a client. */
132
+ addClient(client: FakeAuthioClient): void;
133
+ /** Registers a person. */
134
+ addUser(user: FakeAuthioUser): void;
135
+ /**
136
+ * Registers an authorization code for a person, as the authorization endpoint would after sign-in.
137
+ */
138
+ createAuthorizationCode(options: {
139
+ clientId: string;
140
+ username: string;
141
+ redirectUri: string;
142
+ scope?: string;
143
+ codeChallengeVerifier?: string;
144
+ resource?: string;
145
+ }): string;
146
+ /**
147
+ * Mints an access token signed by the realm key, recorded so introspection and revocation know it.
148
+ */
149
+ issueAccessToken(options?: FakeAuthioTokenOptions): Promise<string>;
150
+ /** Marks a token revoked, as Authio would after a sign-out. */
151
+ revokeToken(token: string): void;
152
+ /** Forgets the recorded requests. */
153
+ clearRequests(): void;
154
+ /** The recorded requests to one endpoint path suffix, such as `/token`. */
155
+ requestsTo(suffix: string): FakeAuthioRecordedRequest[];
156
+ /** Stops the server. */
157
+ close(): Promise<void>;
158
+ private listen;
159
+ private handle;
160
+ private discovery;
161
+ private authenticate;
162
+ private token;
163
+ private tokenAnswer;
164
+ private introspect;
165
+ private revoke;
166
+ private device;
167
+ private userInfo;
168
+ private requireUser;
169
+ }
170
+
171
+ /**
172
+ * A clock that moves only when told to. `sleep` returns at once and moves the clock forward by the time asked, so
173
+ * device polling and cache expiry run instantly and deterministically.
174
+ */
175
+ declare class ManualClock implements AuthioClock {
176
+ /** Every `sleep` asked for, in milliseconds. */
177
+ readonly sleeps: number[];
178
+ private time;
179
+ /**
180
+ * @param start Milliseconds since the epoch. Defaults to the current time.
181
+ */
182
+ constructor(start?: number);
183
+ now(): number;
184
+ sleep(ms: number, signal?: AbortSignal): Promise<void>;
185
+ /** Moves the clock forward. */
186
+ advance(ms: number): void;
187
+ /** Sets the clock. */
188
+ set(ms: number): void;
189
+ }
190
+
191
+ /**
192
+ * A webhook delivery as Authio would send it.
193
+ */
194
+ interface FakeWebhookDelivery {
195
+ readonly body: string;
196
+ readonly headers: Record<string, string>;
197
+ readonly event: Record<string, unknown>;
198
+ }
199
+ /**
200
+ * Builds a signed webhook delivery.
201
+ *
202
+ * @param type The event type.
203
+ * @param data The event data.
204
+ * @param secret The webhook secret.
205
+ * @param options `id`, `timestamp` (milliseconds) and extra event members.
206
+ */
207
+ declare function createWebhookDelivery(type: string, data: unknown, secret: string, options?: {
208
+ id?: string;
209
+ timestamp?: number;
210
+ realmId?: string;
211
+ clientId?: string;
212
+ sendEventIdHeader?: boolean;
213
+ }): Promise<FakeWebhookDelivery>;
214
+
215
+ export { FakeAuthio, type FakeAuthioClient, type FakeAuthioDeviceOutcome, type FakeAuthioError, type FakeAuthioOptions, type FakeAuthioRecordedRequest, type FakeAuthioTokenOptions, type FakeAuthioUser, type FakeWebhookDelivery, ManualClock, createWebhookDelivery };