@crossauth/sveltekit 1.1.0 → 1.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.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -6181
- package/dist/sveltekitadminclientendpoints.d.ts +13 -12
- package/dist/sveltekitadminclientendpoints.js +187 -0
- package/dist/sveltekitadminendpoints.d.ts +5 -4
- package/dist/sveltekitadminendpoints.js +766 -0
- package/dist/sveltekitapikey.d.ts +4 -4
- package/dist/sveltekitapikey.js +81 -0
- package/dist/sveltekitoauthclient.d.ts +6 -5
- package/dist/sveltekitoauthclient.js +2309 -0
- package/dist/sveltekitoauthserver.d.ts +4 -4
- package/dist/sveltekitoauthserver.js +1350 -0
- package/dist/sveltekitresserver.d.ts +6 -5
- package/dist/sveltekitresserver.js +286 -0
- package/dist/sveltekitserver.d.ts +11 -10
- package/dist/sveltekitserver.js +393 -0
- package/dist/sveltekitsession.d.ts +5 -5
- package/dist/sveltekitsession.js +1112 -0
- package/dist/sveltekitsessionadapter.d.ts +2 -3
- package/dist/sveltekitsessionadapter.js +2 -0
- package/dist/sveltekitsharedclientendpoints.d.ts +7 -6
- package/dist/sveltekitsharedclientendpoints.js +630 -0
- package/dist/sveltekituserclientendpoints.d.ts +13 -12
- package/dist/sveltekituserclientendpoints.js +270 -0
- package/dist/sveltekituserendpoints.d.ts +6 -5
- package/dist/sveltekituserendpoints.js +1813 -0
- package/dist/tests/sveltekitadminclientendpoints.test.js +330 -0
- package/dist/tests/sveltekitadminendpoints.test.js +242 -0
- package/dist/tests/sveltekitapikeyserver.test.js +44 -0
- package/dist/tests/sveltekitoauthclient.test.d.ts +5 -5
- package/dist/tests/sveltekitoauthclient.test.js +1016 -0
- package/dist/tests/sveltekitoauthresserver.test.d.ts +4 -4
- package/dist/tests/sveltekitoauthresserver.test.js +185 -0
- package/dist/tests/sveltekitoauthserver.test.js +673 -0
- package/dist/tests/sveltekituserclientendpoints.test.js +244 -0
- package/dist/tests/sveltekituserendpoints.test.js +152 -0
- package/dist/tests/sveltemock.test.js +36 -0
- package/dist/tests/sveltemocks.d.ts +2 -3
- package/dist/tests/sveltemocks.js +114 -0
- package/dist/tests/sveltesessionhooks.test.js +224 -0
- package/dist/tests/testshared.d.ts +8 -8
- package/dist/tests/testshared.js +344 -0
- package/dist/utils.d.ts +1 -2
- package/dist/utils.js +123 -0
- package/package.json +6 -4
- package/dist/index.cjs +0 -1
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
// Copyright (c) 2026 Matthew Baker. All rights reserved. Licenced under the Apache Licence 2.0. See LICENSE file
|
|
2
|
+
import { MockRequestEvent } from './sveltemocks';
|
|
3
|
+
import { test, expect } from 'vitest';
|
|
4
|
+
import { makeServer, getCsrfToken, login } from './testshared';
|
|
5
|
+
export var passwordResetData;
|
|
6
|
+
test('SvelteKitOAuthServer.authorizeRedirectsToLogin', async () => {
|
|
7
|
+
const { server } = await makeServer(true, false, true);
|
|
8
|
+
const redirect = encodeURIComponent("http://example.com/redirect");
|
|
9
|
+
// authorize get endpoint
|
|
10
|
+
let getRequest = new Request(`http://server.com/authorize?response_type=code&client_id=ABC&redirect_uri=${redirect}&scope=read+write&state=ABC123`, {
|
|
11
|
+
method: "GET",
|
|
12
|
+
});
|
|
13
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
14
|
+
let authServer = server.oAuthAuthServer;
|
|
15
|
+
let redirectTo = undefined;
|
|
16
|
+
try {
|
|
17
|
+
await authServer?.authorizeEndpoint.load(event);
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
21
|
+
}
|
|
22
|
+
expect(redirectTo).toContain("/login");
|
|
23
|
+
});
|
|
24
|
+
test('SvelteKitOAuthServer.getAccessTokenWhileLoggedIn', async () => {
|
|
25
|
+
const { server, resolver, handle } = await makeServer(true, false, true);
|
|
26
|
+
// log in
|
|
27
|
+
let resp = await login(server, resolver, handle);
|
|
28
|
+
const user = resp.event.locals.user;
|
|
29
|
+
let loginEvent = resp.event;
|
|
30
|
+
loginEvent = resp.event;
|
|
31
|
+
let sessionCookieValue = loginEvent.cookies.get("SESSIONID");
|
|
32
|
+
// authorize get endpoint
|
|
33
|
+
const redirect = encodeURIComponent("http://example.com/redirect");
|
|
34
|
+
let getRequest = new Request(`http://server.com/authorize?response_type=code&client_id=ABC&redirect_uri=${redirect}&scope=read+write&state=ABC123`, {
|
|
35
|
+
method: "GET",
|
|
36
|
+
headers: [
|
|
37
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
38
|
+
]
|
|
39
|
+
});
|
|
40
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
41
|
+
event.locals.user = user;
|
|
42
|
+
let authServer = server.oAuthAuthServer;
|
|
43
|
+
if (!authServer)
|
|
44
|
+
throw new Error("No auth server");
|
|
45
|
+
let redirectTo = undefined;
|
|
46
|
+
try {
|
|
47
|
+
const resp = await authServer?.authorizeEndpoint.load(event);
|
|
48
|
+
expect(resp?.ok).toBe(true);
|
|
49
|
+
expect(resp?.authorizationNeeded).toBeDefined();
|
|
50
|
+
expect(resp?.authorizationNeeded?.user?.username).toBe("bob");
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
54
|
+
}
|
|
55
|
+
expect(redirectTo).toBeUndefined();
|
|
56
|
+
const { csrfToken, csrfCookieValue } = await getCsrfToken(server, resolver, handle);
|
|
57
|
+
let sessionId = server.sessionServer?.sessionManager.getSessionId(sessionCookieValue ?? "");
|
|
58
|
+
// authorize
|
|
59
|
+
let postRequest = new Request("http://ex.com/authorize", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: "csrfToken=" + csrfToken + "&" +
|
|
62
|
+
"response_type=code&" +
|
|
63
|
+
"client_id=ABC&" +
|
|
64
|
+
"redirect_uri=" + redirect + "&" +
|
|
65
|
+
"scope=read+write&" +
|
|
66
|
+
"state=ABC123&" +
|
|
67
|
+
"authorized=true",
|
|
68
|
+
headers: [
|
|
69
|
+
["cookie", "CSRFTOKEN=" + csrfCookieValue],
|
|
70
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
71
|
+
["content-type", "application/x-www-form-urlencoded"],
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
75
|
+
event.locals.user = user;
|
|
76
|
+
event.locals.csrfToken = csrfToken;
|
|
77
|
+
event.locals.sessionId = sessionId;
|
|
78
|
+
try {
|
|
79
|
+
await authServer?.authorizeEndpoint.actions.default(event);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
83
|
+
}
|
|
84
|
+
expect(redirectTo).toContain("http://example.com/redirect");
|
|
85
|
+
const redirectUrl = new URL(redirectTo ?? "");
|
|
86
|
+
let code = redirectUrl.searchParams.get("code");
|
|
87
|
+
// token
|
|
88
|
+
postRequest = new Request("http://ex.com/token", {
|
|
89
|
+
method: "POST",
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
grant_type: "authorization_code",
|
|
92
|
+
client_id: "ABC",
|
|
93
|
+
client_secret: "DEF",
|
|
94
|
+
scope: "read write",
|
|
95
|
+
code: code,
|
|
96
|
+
}),
|
|
97
|
+
headers: [
|
|
98
|
+
["content-type", "application/json"],
|
|
99
|
+
]
|
|
100
|
+
});
|
|
101
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
102
|
+
let access_token = undefined;
|
|
103
|
+
try {
|
|
104
|
+
const resp = await authServer.tokenEndpoint.post(event);
|
|
105
|
+
access_token = (await resp.json()).access_token;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
109
|
+
}
|
|
110
|
+
expect(access_token).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
test('SvelteKitOAuthServer.alreadyAuthorized', async () => {
|
|
113
|
+
const { server, resolver, handle } = await makeServer(true, false, true);
|
|
114
|
+
// log in
|
|
115
|
+
let resp = await login(server, resolver, handle);
|
|
116
|
+
const user = resp.event.locals.user;
|
|
117
|
+
let loginEvent = resp.event;
|
|
118
|
+
loginEvent = resp.event;
|
|
119
|
+
let sessionCookieValue = loginEvent.cookies.get("SESSIONID");
|
|
120
|
+
// authorize get endpoint
|
|
121
|
+
const redirect = encodeURIComponent("http://example.com/redirect");
|
|
122
|
+
let getRequest = new Request(`http://server.com/authorize?response_type=code&client_id=ABC&redirect_uri=${redirect}&scope=read+write&state=ABC123`, {
|
|
123
|
+
method: "GET",
|
|
124
|
+
headers: [
|
|
125
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
126
|
+
]
|
|
127
|
+
});
|
|
128
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
129
|
+
event.locals.user = user;
|
|
130
|
+
let authServer = server.oAuthAuthServer;
|
|
131
|
+
if (!authServer)
|
|
132
|
+
throw new Error("No auth server");
|
|
133
|
+
let redirectTo = undefined;
|
|
134
|
+
try {
|
|
135
|
+
const resp = await authServer?.authorizeEndpoint.load(event);
|
|
136
|
+
expect(resp?.ok).toBe(true);
|
|
137
|
+
expect(resp?.authorizationNeeded).toBeDefined();
|
|
138
|
+
expect(resp?.authorizationNeeded?.user?.username).toBe("bob");
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
142
|
+
}
|
|
143
|
+
expect(redirectTo).toBeUndefined();
|
|
144
|
+
const { csrfToken, csrfCookieValue } = await getCsrfToken(server, resolver, handle);
|
|
145
|
+
let sessionId = server.sessionServer?.sessionManager.getSessionId(sessionCookieValue ?? "");
|
|
146
|
+
// authorize
|
|
147
|
+
let postRequest = new Request("http://ex.com/authorize", {
|
|
148
|
+
method: "POST",
|
|
149
|
+
body: "csrfToken=" + csrfToken + "&" +
|
|
150
|
+
"response_type=code&" +
|
|
151
|
+
"client_id=ABC&" +
|
|
152
|
+
"redirect_uri=" + redirect + "&" +
|
|
153
|
+
"scope=read+write&" +
|
|
154
|
+
"state=ABC123&" +
|
|
155
|
+
"authorized=true",
|
|
156
|
+
headers: [
|
|
157
|
+
["cookie", "CSRFTOKEN=" + csrfCookieValue],
|
|
158
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
159
|
+
["content-type", "application/x-www-form-urlencoded"],
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
163
|
+
event.locals.user = user;
|
|
164
|
+
event.locals.csrfToken = csrfToken;
|
|
165
|
+
event.locals.sessionId = sessionId;
|
|
166
|
+
try {
|
|
167
|
+
await authServer?.authorizeEndpoint.actions.default(event);
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
171
|
+
}
|
|
172
|
+
expect(redirectTo).toContain("http://example.com/redirect");
|
|
173
|
+
const redirectUrl = new URL(redirectTo ?? "");
|
|
174
|
+
let code = redirectUrl.searchParams.get("code");
|
|
175
|
+
expect(code).toBeDefined();
|
|
176
|
+
// second authorize request
|
|
177
|
+
event = new MockRequestEvent("1", getRequest, {});
|
|
178
|
+
event.locals.user = user;
|
|
179
|
+
redirectTo = undefined;
|
|
180
|
+
try {
|
|
181
|
+
await authServer?.authorizeEndpoint.load(event);
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
185
|
+
}
|
|
186
|
+
expect(redirectTo).toContain("http://example.com/redirect");
|
|
187
|
+
});
|
|
188
|
+
test('SvelteKitOAuthServer.notAuthorized', async () => {
|
|
189
|
+
const { server, resolver, handle } = await makeServer(true, false, true);
|
|
190
|
+
// log in
|
|
191
|
+
let resp = await login(server, resolver, handle);
|
|
192
|
+
const user = resp.event.locals.user;
|
|
193
|
+
let loginEvent = resp.event;
|
|
194
|
+
loginEvent = resp.event;
|
|
195
|
+
let sessionCookieValue = loginEvent.cookies.get("SESSIONID");
|
|
196
|
+
// authorize get endpoint
|
|
197
|
+
const redirect = encodeURIComponent("http://example.com/redirect");
|
|
198
|
+
let getRequest = new Request(`http://server.com/authorize?response_type=code&client_id=ABC&redirect_uri=${redirect}&scope=read+write&state=ABC123`, {
|
|
199
|
+
method: "GET",
|
|
200
|
+
headers: [
|
|
201
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
205
|
+
event.locals.user = user;
|
|
206
|
+
let authServer = server.oAuthAuthServer;
|
|
207
|
+
if (!authServer)
|
|
208
|
+
throw new Error("No auth server");
|
|
209
|
+
let redirectTo = undefined;
|
|
210
|
+
try {
|
|
211
|
+
const resp = await authServer?.authorizeEndpoint.load(event);
|
|
212
|
+
expect(resp?.ok).toBe(true);
|
|
213
|
+
expect(resp?.authorizationNeeded).toBeDefined();
|
|
214
|
+
expect(resp?.authorizationNeeded?.user?.username).toBe("bob");
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
218
|
+
}
|
|
219
|
+
expect(redirectTo).toBeUndefined();
|
|
220
|
+
const { csrfToken, csrfCookieValue } = await getCsrfToken(server, resolver, handle);
|
|
221
|
+
let sessionId = server.sessionServer?.sessionManager.getSessionId(sessionCookieValue ?? "");
|
|
222
|
+
// authorize
|
|
223
|
+
let postRequest = new Request("http://ex.com/authorize", {
|
|
224
|
+
method: "POST",
|
|
225
|
+
body: "csrfToken=" + csrfToken + "&" +
|
|
226
|
+
"response_type=code&" +
|
|
227
|
+
"client_id=ABC&" +
|
|
228
|
+
"redirect_uri=" + redirect + "&" +
|
|
229
|
+
"scope=read+write&" +
|
|
230
|
+
"state=ABC123&" +
|
|
231
|
+
"authorized=false",
|
|
232
|
+
headers: [
|
|
233
|
+
["cookie", "CSRFTOKEN=" + csrfCookieValue],
|
|
234
|
+
["cookie", "SESSIONID=" + sessionCookieValue],
|
|
235
|
+
["content-type", "application/x-www-form-urlencoded"],
|
|
236
|
+
]
|
|
237
|
+
});
|
|
238
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
239
|
+
event.locals.user = user;
|
|
240
|
+
event.locals.csrfToken = csrfToken;
|
|
241
|
+
event.locals.sessionId = sessionId;
|
|
242
|
+
try {
|
|
243
|
+
await authServer?.authorizeEndpoint.actions.default(event);
|
|
244
|
+
}
|
|
245
|
+
catch (e) {
|
|
246
|
+
redirectTo = "location" in Object(e) ? Object(e).location : undefined;
|
|
247
|
+
}
|
|
248
|
+
expect(redirectTo).toContain("http://example.com/redirect");
|
|
249
|
+
const url = new URL(redirectTo ?? "");
|
|
250
|
+
expect(url.searchParams.get("error")).toBe("access_denied");
|
|
251
|
+
});
|
|
252
|
+
test('SvelteKitOAuthServer.oidcConfiguration', async () => {
|
|
253
|
+
const { server } = await makeServer(true, false, true);
|
|
254
|
+
let getRequest = new Request(`http://server.com/oidc-configuration`, {
|
|
255
|
+
method: "GET",
|
|
256
|
+
});
|
|
257
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
258
|
+
let authServer = server.oAuthAuthServer;
|
|
259
|
+
const resp = await authServer?.oidcConfigurationEndpoint.get(event);
|
|
260
|
+
expect(resp?.status).toBe(200);
|
|
261
|
+
const body = await resp?.json();
|
|
262
|
+
expect(body?.authorization_endpoint).toBe("http://localhost:3000/oauth/authorize");
|
|
263
|
+
expect(body?.token_endpoint).toBe("http://localhost:3000/oauth/token");
|
|
264
|
+
expect(body?.jwks_uri).toBe("http://localhost:3000/oauth/jwks");
|
|
265
|
+
});
|
|
266
|
+
test('SvelteKitOAuthServer.jwks', async () => {
|
|
267
|
+
const { server } = await makeServer(true, false, true);
|
|
268
|
+
let getRequest = new Request(`http://server.com/jwks`, {
|
|
269
|
+
method: "GET",
|
|
270
|
+
});
|
|
271
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
272
|
+
let authServer = server.oAuthAuthServer;
|
|
273
|
+
const resp = await authServer?.jwksGetEndpoint.get(event);
|
|
274
|
+
expect(resp?.status).toBe(200);
|
|
275
|
+
const body = await resp?.json();
|
|
276
|
+
expect(body.keys).toBeDefined();
|
|
277
|
+
expect(body.keys.length).toBe(1);
|
|
278
|
+
});
|
|
279
|
+
test('SvelteKitOAuthServer.getCsrfTokenJson', async () => {
|
|
280
|
+
const { server } = await makeServer(true, false, true);
|
|
281
|
+
let getRequest = new Request(`http://server.com/getcsrftoken`, {
|
|
282
|
+
method: "GET",
|
|
283
|
+
});
|
|
284
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
285
|
+
let authServer = server.oAuthAuthServer;
|
|
286
|
+
const resp = await authServer?.getCsrfTokenEndpoint.get(event);
|
|
287
|
+
expect(resp?.status).toBe(200);
|
|
288
|
+
const body = await resp?.json();
|
|
289
|
+
expect(body.ok).toBe(false);
|
|
290
|
+
});
|
|
291
|
+
test('SvelteKitOAuthServer.getCsrfTokenCookie', async () => {
|
|
292
|
+
const { server } = await makeServer(true, false, true, false, { refreshTokenType: "cookie" });
|
|
293
|
+
let getRequest = new Request(`http://server.com/getcsrftoken`, {
|
|
294
|
+
method: "GET",
|
|
295
|
+
});
|
|
296
|
+
let event = new MockRequestEvent("1", getRequest, {});
|
|
297
|
+
let authServer = server.oAuthAuthServer;
|
|
298
|
+
const resp = await authServer?.getCsrfTokenEndpoint.get(event);
|
|
299
|
+
expect(resp?.status).toBe(200);
|
|
300
|
+
const body = await resp?.json();
|
|
301
|
+
expect(body.ok).toBe(true);
|
|
302
|
+
expect(body.csrfToken).toBeDefined();
|
|
303
|
+
});
|
|
304
|
+
test('SvelteKitOAuthServer.mfa', async () => {
|
|
305
|
+
const { server, resolver, handle } = await makeServer(true, false, true);
|
|
306
|
+
// log in
|
|
307
|
+
await login(server, resolver, handle);
|
|
308
|
+
// get OAuth auth server
|
|
309
|
+
let authServer = server.oAuthAuthServer;
|
|
310
|
+
if (!authServer)
|
|
311
|
+
throw new Error("No auth server");
|
|
312
|
+
// token
|
|
313
|
+
let postRequest = new Request("http://ex.com/token", {
|
|
314
|
+
method: "POST",
|
|
315
|
+
body: JSON.stringify({
|
|
316
|
+
grant_type: "password",
|
|
317
|
+
client_id: "ABC",
|
|
318
|
+
client_secret: "DEF",
|
|
319
|
+
scope: "read write",
|
|
320
|
+
username: "alice",
|
|
321
|
+
password: "alicePass123",
|
|
322
|
+
state: "ABCDEF",
|
|
323
|
+
}),
|
|
324
|
+
headers: [
|
|
325
|
+
["content-type", "application/json"],
|
|
326
|
+
]
|
|
327
|
+
});
|
|
328
|
+
let event = new MockRequestEvent("1", postRequest, {});
|
|
329
|
+
const resp2 = await authServer.tokenEndpoint.post(event);
|
|
330
|
+
const body2 = await resp2.json();
|
|
331
|
+
expect(body2.error).toBe("mfa_required");
|
|
332
|
+
const mfa_token = body2.mfa_token ?? "";
|
|
333
|
+
// authenticators
|
|
334
|
+
let getRequest = new Request(`http://server.com/authenticators`, {
|
|
335
|
+
method: "GET",
|
|
336
|
+
headers: {
|
|
337
|
+
'authorization': "Bearer " + mfa_token,
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
event = new MockRequestEvent("1", getRequest, {});
|
|
341
|
+
const resp3 = await authServer.mfaAuthenticatorsEndpoint.get(event);
|
|
342
|
+
const body3 = await resp3.json();
|
|
343
|
+
expect(Array.isArray(body3)).toBe(true);
|
|
344
|
+
expect(body3.length).toBe(1);
|
|
345
|
+
// challenge
|
|
346
|
+
postRequest = new Request("http://ex.com/mfachallenge", {
|
|
347
|
+
method: "POST",
|
|
348
|
+
body: JSON.stringify({
|
|
349
|
+
mfa_token: mfa_token,
|
|
350
|
+
client_id: "ABC",
|
|
351
|
+
client_secret: "DEF",
|
|
352
|
+
authenticator_id: "dummyFactor2",
|
|
353
|
+
challenge_type: "oob",
|
|
354
|
+
}),
|
|
355
|
+
headers: [
|
|
356
|
+
["content-type", "application/json"],
|
|
357
|
+
]
|
|
358
|
+
});
|
|
359
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
360
|
+
const resp4 = await authServer.mfaChallengeEndpoint.post(event);
|
|
361
|
+
const body4 = await resp4.json();
|
|
362
|
+
expect(body4.challenge_type).toBe("oob");
|
|
363
|
+
expect(body4.oob_code).toBeDefined();
|
|
364
|
+
const oob_code = body4.oob_code;
|
|
365
|
+
const oob = "0000";
|
|
366
|
+
// OOB
|
|
367
|
+
postRequest = new Request("http://ex.com/token", {
|
|
368
|
+
method: "POST",
|
|
369
|
+
body: JSON.stringify({
|
|
370
|
+
grant_type: "http://auth0.com/oauth/grant-type/mfa-oob",
|
|
371
|
+
client_id: "ABC",
|
|
372
|
+
scope: "read write",
|
|
373
|
+
client_secret: "DEF",
|
|
374
|
+
mfa_token: mfa_token,
|
|
375
|
+
oob_code: oob_code,
|
|
376
|
+
binding_code: oob
|
|
377
|
+
}),
|
|
378
|
+
headers: [
|
|
379
|
+
["content-type", "application/json"],
|
|
380
|
+
]
|
|
381
|
+
});
|
|
382
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
383
|
+
const resp5 = await authServer.tokenEndpoint.post(event);
|
|
384
|
+
const body5 = await resp5.json();
|
|
385
|
+
expect(body5.access_token).toBeDefined();
|
|
386
|
+
});
|
|
387
|
+
test('SvelteKitOAuthServer.deviceCodeManual', async () => {
|
|
388
|
+
const { server, resolver, handle, userStorage } = await makeServer(true, false, true);
|
|
389
|
+
// log in
|
|
390
|
+
await login(server, resolver, handle);
|
|
391
|
+
// get OAuth auth server
|
|
392
|
+
let authServer = server.oAuthAuthServer;
|
|
393
|
+
if (!authServer)
|
|
394
|
+
throw new Error("No auth server");
|
|
395
|
+
// call device authorization endpoint to create user and device code
|
|
396
|
+
let postRequest = new Request("http://ex.com/dummy", {
|
|
397
|
+
method: "POST",
|
|
398
|
+
body: JSON.stringify({
|
|
399
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
400
|
+
client_id: "ABC",
|
|
401
|
+
client_secret: "DEF",
|
|
402
|
+
scope: "read write",
|
|
403
|
+
}),
|
|
404
|
+
headers: [
|
|
405
|
+
["content-type", "application/json"],
|
|
406
|
+
]
|
|
407
|
+
});
|
|
408
|
+
let event = new MockRequestEvent("1", postRequest, {});
|
|
409
|
+
const devAuthResp = await authServer.deviceAuthorizationEndpoint.post(event);
|
|
410
|
+
let devAuthBody = await devAuthResp.json();
|
|
411
|
+
expect(devAuthBody.device_code).toBeDefined();
|
|
412
|
+
expect(devAuthBody.verification_uri).toBe('http://localhost:5174/device');
|
|
413
|
+
expect(devAuthBody.verification_uri_complete).toContain('http://localhost:5174/device?user_code=');
|
|
414
|
+
expect(devAuthBody.user_code?.length).toBe(9);
|
|
415
|
+
// call device endpoint - should result in a redirect to login page
|
|
416
|
+
let getRequest = new Request("http://ex.com/dummy", {
|
|
417
|
+
method: "GET",
|
|
418
|
+
});
|
|
419
|
+
event = new MockRequestEvent("1", getRequest, {});
|
|
420
|
+
let location = undefined;
|
|
421
|
+
let status = undefined;
|
|
422
|
+
try {
|
|
423
|
+
await authServer.deviceEndpoint.load(event);
|
|
424
|
+
}
|
|
425
|
+
catch (e) {
|
|
426
|
+
location = e.location;
|
|
427
|
+
status = e.status;
|
|
428
|
+
}
|
|
429
|
+
expect(status).toBe(302);
|
|
430
|
+
expect(location).toBe("/login?next=http%3A%2F%2Fex.com%2Fdummy");
|
|
431
|
+
// simulate login
|
|
432
|
+
const user = (await userStorage.getUserByUsername("bob")).user;
|
|
433
|
+
event.locals.user = user;
|
|
434
|
+
// call device endpoint again, without user code. Should return data for showing prompt page
|
|
435
|
+
let devResp = await authServer.deviceEndpoint.load(event);
|
|
436
|
+
expect(devResp.ok).toBe(true);
|
|
437
|
+
expect(devResp.completed).toBe(false);
|
|
438
|
+
expect(devResp.retryAllowed).toBe(true);
|
|
439
|
+
expect(devResp.user?.username).toBe("bob");
|
|
440
|
+
expect(devResp.authorizationNeeded).toBeUndefined();
|
|
441
|
+
// call token endpoint - should return authorization_pending
|
|
442
|
+
let tokenRequest = new Request("http://ex.com/token", {
|
|
443
|
+
method: "POST",
|
|
444
|
+
body: JSON.stringify({
|
|
445
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
446
|
+
client_id: "ABC",
|
|
447
|
+
client_secret: "DEF",
|
|
448
|
+
scope: "read write",
|
|
449
|
+
device_code: devAuthBody.device_code,
|
|
450
|
+
}),
|
|
451
|
+
headers: [
|
|
452
|
+
["content-type", "application/json"],
|
|
453
|
+
]
|
|
454
|
+
});
|
|
455
|
+
let tokenEvent = new MockRequestEvent("1", tokenRequest, {});
|
|
456
|
+
let tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
457
|
+
let tokenBody = await tokenResp.json();
|
|
458
|
+
expect(tokenResp.status).toBe(200);
|
|
459
|
+
expect(tokenBody.error).toBe("authorization_pending");
|
|
460
|
+
// submit wrong user code
|
|
461
|
+
postRequest = new Request("http://ex.com/dummy", {
|
|
462
|
+
method: "POST",
|
|
463
|
+
body: JSON.stringify({
|
|
464
|
+
user_code: "XXX",
|
|
465
|
+
}),
|
|
466
|
+
headers: [
|
|
467
|
+
["content-type", "application/json"],
|
|
468
|
+
]
|
|
469
|
+
});
|
|
470
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
471
|
+
event.locals.user = user;
|
|
472
|
+
let devPostResp = await authServer.deviceEndpoint.actions.userCode(event);
|
|
473
|
+
expect(devPostResp.ok).toBe(false);
|
|
474
|
+
expect(devPostResp.error).toBe("access_denied");
|
|
475
|
+
// token should still return authorization_pending
|
|
476
|
+
tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
477
|
+
tokenBody = await tokenResp.json();
|
|
478
|
+
expect(tokenResp.status).toBe(200);
|
|
479
|
+
expect(tokenBody.error).toBe("authorization_pending");
|
|
480
|
+
// submit right user code
|
|
481
|
+
postRequest = new Request("http://ex.com/dummy", {
|
|
482
|
+
method: "POST",
|
|
483
|
+
body: JSON.stringify({
|
|
484
|
+
user_code: devAuthBody.user_code,
|
|
485
|
+
}),
|
|
486
|
+
headers: [
|
|
487
|
+
["content-type", "application/json"],
|
|
488
|
+
]
|
|
489
|
+
});
|
|
490
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
491
|
+
event.locals.user = user;
|
|
492
|
+
devPostResp = await authServer.deviceEndpoint.actions.userCode(event);
|
|
493
|
+
expect(devPostResp.ok).toBe(true);
|
|
494
|
+
expect(devPostResp.completed).toBe(false);
|
|
495
|
+
expect(devPostResp.authorizationNeeded?.user?.username).toBe("bob");
|
|
496
|
+
expect(devPostResp.authorizationNeeded?.client_id).toBe("ABC");
|
|
497
|
+
expect(devPostResp.authorizationNeeded?.scope).toBe("read write");
|
|
498
|
+
expect(devPostResp.user_code).toBe(devAuthBody.user_code);
|
|
499
|
+
// authorize scopes
|
|
500
|
+
authServer.authServer.validateAndPersistScope("ABC", "read write", user);
|
|
501
|
+
// submit user code again
|
|
502
|
+
devPostResp = await authServer.deviceEndpoint.actions.userCode(event);
|
|
503
|
+
expect(devPostResp.ok).toBe(true);
|
|
504
|
+
expect(devPostResp.completed).toBe(true);
|
|
505
|
+
// token should return access_token
|
|
506
|
+
tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
507
|
+
tokenBody = await tokenResp.json();
|
|
508
|
+
expect(tokenResp.status).toBe(200);
|
|
509
|
+
expect(tokenBody.error).toBeUndefined();
|
|
510
|
+
expect(tokenBody.access_token).toBeDefined();
|
|
511
|
+
});
|
|
512
|
+
test('SvelteKitOAuthServer.deviceCodeAuto', async () => {
|
|
513
|
+
const { server, resolver, handle, userStorage } = await makeServer(true, false, true);
|
|
514
|
+
// log in
|
|
515
|
+
await login(server, resolver, handle);
|
|
516
|
+
// get OAuth auth server
|
|
517
|
+
let authServer = server.oAuthAuthServer;
|
|
518
|
+
if (!authServer)
|
|
519
|
+
throw new Error("No auth server");
|
|
520
|
+
// call device authorization endpoint to create user and device code
|
|
521
|
+
let postRequest = new Request("http://ex.com/dummy", {
|
|
522
|
+
method: "POST",
|
|
523
|
+
body: JSON.stringify({
|
|
524
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
525
|
+
client_id: "ABC",
|
|
526
|
+
client_secret: "DEF",
|
|
527
|
+
scope: "read write",
|
|
528
|
+
}),
|
|
529
|
+
headers: [
|
|
530
|
+
["content-type", "application/json"],
|
|
531
|
+
]
|
|
532
|
+
});
|
|
533
|
+
let event = new MockRequestEvent("1", postRequest, {});
|
|
534
|
+
const devAuthResp = await authServer.deviceAuthorizationEndpoint.post(event);
|
|
535
|
+
let devAuthBody = await devAuthResp.json();
|
|
536
|
+
expect(devAuthBody.device_code).toBeDefined();
|
|
537
|
+
expect(devAuthBody.verification_uri).toBe('http://localhost:5174/device');
|
|
538
|
+
expect(devAuthBody.verification_uri_complete).toContain('http://localhost:5174/device?user_code=');
|
|
539
|
+
expect(devAuthBody.user_code?.length).toBe(9);
|
|
540
|
+
// call device endpoint - should result in a redirect to login page
|
|
541
|
+
let getRequest = new Request("http://ex.com/dummy?user_code=" + devAuthBody.user_code, {
|
|
542
|
+
method: "GET",
|
|
543
|
+
});
|
|
544
|
+
event = new MockRequestEvent("1", getRequest, {});
|
|
545
|
+
let location = undefined;
|
|
546
|
+
let status = undefined;
|
|
547
|
+
try {
|
|
548
|
+
await authServer.deviceEndpoint.load(event);
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
location = e.location;
|
|
552
|
+
status = e.status;
|
|
553
|
+
}
|
|
554
|
+
expect(status).toBe(302);
|
|
555
|
+
expect(location).toContain("/login?next=http%3A%2F%2Fex.com%2Fdummy%3Fuser_code%3D");
|
|
556
|
+
// simulate login
|
|
557
|
+
const user = (await userStorage.getUserByUsername("bob")).user;
|
|
558
|
+
event.locals.user = user;
|
|
559
|
+
// call device endpoint again, without user code. Should return data for showing prompt page
|
|
560
|
+
let devResp = await authServer.deviceEndpoint.load(event);
|
|
561
|
+
expect(devResp.ok).toBe(true);
|
|
562
|
+
expect(devResp.completed).toBe(false);
|
|
563
|
+
expect(devResp.retryAllowed).toBe(true);
|
|
564
|
+
expect(devResp.user?.username).toBe("bob");
|
|
565
|
+
expect(devResp.authorizationNeeded).toBeDefined();
|
|
566
|
+
expect(devResp.user_code?.length).toBe(9);
|
|
567
|
+
// authorize scopes
|
|
568
|
+
authServer.authServer.validateAndPersistScope("ABC", "read write", user);
|
|
569
|
+
// call token endpoint - should return authorization_pending
|
|
570
|
+
let tokenRequest = new Request("http://ex.com/token", {
|
|
571
|
+
method: "POST",
|
|
572
|
+
body: JSON.stringify({
|
|
573
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
574
|
+
client_id: "ABC",
|
|
575
|
+
client_secret: "DEF",
|
|
576
|
+
scope: "read write",
|
|
577
|
+
device_code: devAuthBody.device_code,
|
|
578
|
+
}),
|
|
579
|
+
headers: [
|
|
580
|
+
["content-type", "application/json"],
|
|
581
|
+
]
|
|
582
|
+
});
|
|
583
|
+
let tokenEvent = new MockRequestEvent("1", tokenRequest, {});
|
|
584
|
+
let tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
585
|
+
let tokenBody = await tokenResp.json();
|
|
586
|
+
expect(tokenResp.status).toBe(200);
|
|
587
|
+
expect(tokenBody.error).toBe("authorization_pending");
|
|
588
|
+
// submit post with user code
|
|
589
|
+
postRequest = new Request("http://ex.com/dummy", {
|
|
590
|
+
method: "POST",
|
|
591
|
+
body: JSON.stringify({
|
|
592
|
+
user_code: devResp.user_code,
|
|
593
|
+
}),
|
|
594
|
+
headers: [
|
|
595
|
+
["content-type", "application/json"],
|
|
596
|
+
]
|
|
597
|
+
});
|
|
598
|
+
event = new MockRequestEvent("1", postRequest, {});
|
|
599
|
+
event.locals.user = user;
|
|
600
|
+
let devPostResp = await authServer.deviceEndpoint.actions.userCode(event);
|
|
601
|
+
expect(devPostResp.ok).toBe(true);
|
|
602
|
+
expect(devPostResp.completed).toBe(true);
|
|
603
|
+
expect(devPostResp.authorizationNeeded).toBeUndefined();
|
|
604
|
+
// token should return access_token
|
|
605
|
+
tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
606
|
+
tokenBody = await tokenResp.json();
|
|
607
|
+
expect(tokenResp.status).toBe(200);
|
|
608
|
+
expect(tokenBody.error).toBeUndefined();
|
|
609
|
+
expect(tokenBody.access_token).toBeDefined();
|
|
610
|
+
});
|
|
611
|
+
test('SvelteKitOAuthServer.deviceCodeAutoPreAuthorizePreLogin', async () => {
|
|
612
|
+
const { server, resolver, handle, userStorage } = await makeServer(true, false, true);
|
|
613
|
+
// log in
|
|
614
|
+
await login(server, resolver, handle);
|
|
615
|
+
// get OAuth auth server
|
|
616
|
+
let authServer = server.oAuthAuthServer;
|
|
617
|
+
if (!authServer)
|
|
618
|
+
throw new Error("No auth server");
|
|
619
|
+
// call device authorization endpoint to create user and device code
|
|
620
|
+
let postRequest = new Request("http://ex.com/dummy", {
|
|
621
|
+
method: "POST",
|
|
622
|
+
body: JSON.stringify({
|
|
623
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
624
|
+
client_id: "ABC",
|
|
625
|
+
client_secret: "DEF",
|
|
626
|
+
scope: "read write",
|
|
627
|
+
}),
|
|
628
|
+
headers: [
|
|
629
|
+
["content-type", "application/json"],
|
|
630
|
+
]
|
|
631
|
+
});
|
|
632
|
+
let event = new MockRequestEvent("1", postRequest, {});
|
|
633
|
+
const devAuthResp = await authServer.deviceAuthorizationEndpoint.post(event);
|
|
634
|
+
let devAuthBody = await devAuthResp.json();
|
|
635
|
+
expect(devAuthBody.device_code).toBeDefined();
|
|
636
|
+
expect(devAuthBody.verification_uri).toBe('http://localhost:5174/device');
|
|
637
|
+
expect(devAuthBody.verification_uri_complete).toContain('http://localhost:5174/device?user_code=');
|
|
638
|
+
expect(devAuthBody.user_code?.length).toBe(9);
|
|
639
|
+
const user = (await userStorage.getUserByUsername("bob")).user;
|
|
640
|
+
// authorize scopes
|
|
641
|
+
authServer.authServer.validateAndPersistScope("ABC", "read write", user);
|
|
642
|
+
// call device endpoint - should result in a redirect to login page
|
|
643
|
+
let getRequest = new Request("http://ex.com/dummy?user_code=" + devAuthBody.user_code, {
|
|
644
|
+
method: "GET",
|
|
645
|
+
});
|
|
646
|
+
event = new MockRequestEvent("1", getRequest, {});
|
|
647
|
+
event.locals.user = user;
|
|
648
|
+
let devResp = await authServer.deviceEndpoint.load(event);
|
|
649
|
+
expect(devResp.ok).toBe(true);
|
|
650
|
+
expect(devResp.completed).toBe(true);
|
|
651
|
+
expect(devResp.user?.username).toBe("bob");
|
|
652
|
+
expect(devResp.authorizationNeeded).toBeUndefined();
|
|
653
|
+
// call token endpoint - should return access token
|
|
654
|
+
let tokenRequest = new Request("http://ex.com/token", {
|
|
655
|
+
method: "POST",
|
|
656
|
+
body: JSON.stringify({
|
|
657
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
658
|
+
client_id: "ABC",
|
|
659
|
+
client_secret: "DEF",
|
|
660
|
+
scope: "read write",
|
|
661
|
+
device_code: devAuthBody.device_code,
|
|
662
|
+
}),
|
|
663
|
+
headers: [
|
|
664
|
+
["content-type", "application/json"],
|
|
665
|
+
]
|
|
666
|
+
});
|
|
667
|
+
let tokenEvent = new MockRequestEvent("1", tokenRequest, {});
|
|
668
|
+
let tokenResp = await authServer.tokenEndpoint.post(tokenEvent);
|
|
669
|
+
let tokenBody = await tokenResp.json();
|
|
670
|
+
expect(tokenResp.status).toBe(200);
|
|
671
|
+
expect(tokenBody.error).toBeUndefined();
|
|
672
|
+
expect(tokenBody.access_token).toBeDefined();
|
|
673
|
+
});
|