@better-auth/sso 1.4.0-beta.4 → 1.4.0-beta.6

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @better-auth/sso@1.4.0-beta.4 build /home/runner/work/better-auth/better-auth/packages/sso
2
+ > @better-auth/sso@1.4.0-beta.6 build /home/runner/work/better-auth/better-auth/packages/sso
3
3
  > unbuild
4
4
 
5
5
  [info] Automatically detected entries: src/index, src/client [esm] [cjs] [dts]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@better-auth/sso",
3
3
  "author": "Bereket Engida",
4
- "version": "1.4.0-beta.4",
4
+ "version": "1.4.0-beta.6",
5
5
  "main": "dist/index.cjs",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -58,10 +58,10 @@
58
58
  "body-parser": "^2.2.0",
59
59
  "express": "^5.1.0",
60
60
  "unbuild": "3.6.1",
61
- "better-auth": "^1.4.0-beta.4"
61
+ "better-auth": "^1.4.0-beta.6"
62
62
  },
63
63
  "peerDependencies": {
64
- "better-auth": "1.4.0-beta.4"
64
+ "better-auth": "1.4.0-beta.6"
65
65
  },
66
66
  "scripts": {
67
67
  "test": "vitest",
package/src/oidc.test.ts CHANGED
@@ -1,18 +1,28 @@
1
1
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
+ import { getTestInstanceMemory as getTestInstance } from "better-auth/test";
2
3
  import { sso } from ".";
3
4
  import { OAuth2Server } from "oauth2-mock-server";
4
5
  import { betterFetch } from "@better-fetch/fetch";
5
- import { organization } from "better-auth/plugins/organization";
6
- import { getTestInstanceMemory } from "better-auth/test";
6
+ import { organization } from "better-auth/plugins";
7
+ import { createAuthClient } from "better-auth/client";
8
+ import { ssoClient } from "./client";
7
9
 
8
10
  let server = new OAuth2Server();
9
11
 
10
12
  describe("SSO", async () => {
11
- const { auth, signInWithTestUser, customFetchImpl } =
12
- await getTestInstanceMemory({
13
+ const { auth, signInWithTestUser, customFetchImpl, cookieSetter } =
14
+ await getTestInstance({
13
15
  plugins: [sso(), organization()],
14
16
  });
15
17
 
18
+ const authClient = createAuthClient({
19
+ plugins: [ssoClient()],
20
+ baseURL: "http://localhost:3000",
21
+ fetchOptions: {
22
+ customFetchImpl,
23
+ },
24
+ });
25
+
16
26
  beforeAll(async () => {
17
27
  await server.issuer.keys.generate("RS256");
18
28
  server.issuer.on;
@@ -57,7 +67,7 @@ describe("SSO", async () => {
57
67
  });
58
68
 
59
69
  if (!location) throw new Error("No redirect location found");
60
-
70
+ const newHeaders = new Headers();
61
71
  let callbackURL = "";
62
72
  await betterFetch(location, {
63
73
  method: "GET",
@@ -65,10 +75,11 @@ describe("SSO", async () => {
65
75
  headers,
66
76
  onError(context) {
67
77
  callbackURL = context.response.headers.get("location") || "";
78
+ cookieSetter(newHeaders)(context);
68
79
  },
69
80
  });
70
81
 
71
- return callbackURL;
82
+ return { callbackURL, headers: newHeaders };
72
83
  }
73
84
 
74
85
  it("should register a new SSO provider", async () => {
@@ -147,122 +158,76 @@ describe("SSO", async () => {
147
158
  });
148
159
 
149
160
  it("should sign in with SSO provider with email matching", async () => {
150
- const res = await auth.api.signInSSO({
151
- body: {
152
- email: "my-email@localhost.com",
153
- callbackURL: "/dashboard",
161
+ const headers = new Headers();
162
+ const res = await authClient.signIn.sso({
163
+ email: "my-email@localhost.com",
164
+ callbackURL: "/dashboard",
165
+ fetchOptions: {
166
+ throw: true,
167
+ onSuccess: cookieSetter(headers),
154
168
  },
155
169
  });
156
170
  expect(res.url).toContain("http://localhost:8080/authorize");
157
171
  expect(res.url).toContain(
158
172
  "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
159
173
  );
160
- const headers = new Headers();
161
- const callbackURL = await simulateOAuthFlow(res.url, headers);
174
+ const { callbackURL } = await simulateOAuthFlow(res.url, headers);
162
175
  expect(callbackURL).toContain("/dashboard");
163
176
  });
164
177
 
165
178
  it("should sign in with SSO provider with domain", async () => {
166
- const res = await auth.api.signInSSO({
167
- body: {
168
- email: "my-email@test.com",
169
- domain: "localhost.com",
170
- callbackURL: "/dashboard",
179
+ const headers = new Headers();
180
+ const res = await authClient.signIn.sso({
181
+ email: "my-email@test.com",
182
+ domain: "localhost.com",
183
+ callbackURL: "/dashboard",
184
+ fetchOptions: {
185
+ throw: true,
186
+ onSuccess: cookieSetter(headers),
171
187
  },
172
188
  });
173
189
  expect(res.url).toContain("http://localhost:8080/authorize");
174
190
  expect(res.url).toContain(
175
191
  "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
176
192
  );
177
- const headers = new Headers();
178
- const callbackURL = await simulateOAuthFlow(res.url, headers);
193
+ const { callbackURL } = await simulateOAuthFlow(res.url, headers);
179
194
  expect(callbackURL).toContain("/dashboard");
180
195
  });
181
196
 
182
197
  it("should sign in with SSO provider with providerId", async () => {
183
- const res = await auth.api.signInSSO({
184
- body: {
185
- providerId: "test",
186
- callbackURL: "/dashboard",
187
- },
188
- });
189
- expect(res.url).toContain("http://localhost:8080/authorize");
190
- expect(res.url).toContain(
191
- "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
192
- );
193
198
  const headers = new Headers();
194
- const callbackURL = await simulateOAuthFlow(res.url, headers);
195
- expect(callbackURL).toContain("/dashboard");
196
- });
197
- });
198
-
199
- describe("SSO with defaultSSO array", async () => {
200
- const { auth, signInWithTestUser, customFetchImpl } =
201
- await getTestInstanceMemory({
202
- plugins: [
203
- sso({
204
- defaultSSO: [
205
- {
206
- domain: "localhost.com",
207
- providerId: "default-test",
208
- oidcConfig: {
209
- issuer: "http://localhost:8080",
210
- clientId: "test",
211
- clientSecret: "test",
212
- authorizationEndpoint: "http://localhost:8080/authorize",
213
- tokenEndpoint: "http://localhost:8080/token",
214
- jwksEndpoint: "http://localhost:8080/jwks",
215
- discoveryEndpoint:
216
- "http://localhost:8080/.well-known/openid-configuration",
217
- pkce: true,
218
- mapping: {
219
- id: "sub",
220
- email: "email",
221
- emailVerified: "email_verified",
222
- name: "name",
223
- image: "picture",
224
- },
225
- },
226
- },
227
- ],
228
- }),
229
- organization(),
230
- ],
231
- });
232
-
233
- it("should use default SSO provider from array when no provider found in database using providerId", async () => {
234
- const res = await auth.api.signInSSO({
235
- body: {
236
- providerId: "default-test",
237
- callbackURL: "/dashboard",
199
+ const res = await authClient.signIn.sso({
200
+ providerId: "test",
201
+ callbackURL: "/dashboard",
202
+ fetchOptions: {
203
+ throw: true,
204
+ onSuccess: cookieSetter(headers),
238
205
  },
239
206
  });
240
207
  expect(res.url).toContain("http://localhost:8080/authorize");
241
208
  expect(res.url).toContain(
242
- "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Fdefault-test",
209
+ "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
243
210
  );
244
- });
245
211
 
246
- it("should use default SSO provider from array when no provider found in database using domain fallback", async () => {
247
- const res = await auth.api.signInSSO({
248
- body: {
249
- email: "test@localhost.com",
250
- callbackURL: "/dashboard",
251
- },
252
- });
253
- expect(res.url).toContain("http://localhost:8080/authorize");
254
- expect(res.url).toContain(
255
- "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Fdefault-test",
256
- );
212
+ const { callbackURL } = await simulateOAuthFlow(res.url, headers);
213
+ expect(callbackURL).toContain("/dashboard");
257
214
  });
258
215
  });
259
216
 
260
217
  describe("SSO disable implicit sign in", async () => {
261
- const { auth, signInWithTestUser, customFetchImpl } =
262
- await getTestInstanceMemory({
218
+ const { auth, signInWithTestUser, customFetchImpl, cookieSetter } =
219
+ await getTestInstance({
263
220
  plugins: [sso({ disableImplicitSignUp: true }), organization()],
264
221
  });
265
222
 
223
+ const authClient = createAuthClient({
224
+ plugins: [ssoClient()],
225
+ baseURL: "http://localhost:3000",
226
+ fetchOptions: {
227
+ customFetchImpl,
228
+ },
229
+ });
230
+
266
231
  beforeAll(async () => {
267
232
  await server.issuer.keys.generate("RS256");
268
233
  server.issuer.on;
@@ -307,7 +272,7 @@ describe("SSO disable implicit sign in", async () => {
307
272
  });
308
273
 
309
274
  if (!location) throw new Error("No redirect location found");
310
-
275
+ const newHeaders = new Headers(headers);
311
276
  let callbackURL = "";
312
277
  await betterFetch(location, {
313
278
  method: "GET",
@@ -315,10 +280,11 @@ describe("SSO disable implicit sign in", async () => {
315
280
  headers,
316
281
  onError(context) {
317
282
  callbackURL = context.response.headers.get("location") || "";
283
+ cookieSetter(newHeaders)(context);
318
284
  },
319
285
  });
320
286
 
321
- return callbackURL;
287
+ return { callbackURL, headers: newHeaders };
322
288
  }
323
289
 
324
290
  it("should register a new SSO provider", async () => {
@@ -369,150 +335,61 @@ describe("SSO disable implicit sign in", async () => {
369
335
  userId: expect.any(String),
370
336
  });
371
337
  });
372
- it("should not allow creating a provider if limit is set to 0", async () => {
373
- const { auth, signInWithTestUser } = await getTestInstanceMemory({
374
- plugins: [sso({ providersLimit: 0 })],
375
- });
376
- const { headers } = await signInWithTestUser();
377
- await expect(
378
- auth.api.registerSSOProvider({
379
- body: {
380
- issuer: server.issuer.url!,
381
- domain: "localhost.com",
382
- oidcConfig: {
383
- clientId: "test",
384
- clientSecret: "test",
385
- },
386
- providerId: "test",
387
- },
388
- headers,
389
- }),
390
- ).rejects.toMatchObject({
391
- status: "FORBIDDEN",
392
- body: { message: "SSO provider registration is disabled" },
393
- });
394
- });
395
- it("should not allow creating a provider if limit is reached", async () => {
396
- const { auth, signInWithTestUser } = await getTestInstanceMemory({
397
- plugins: [sso({ providersLimit: 1 })],
398
- });
399
- const { headers } = await signInWithTestUser();
400
-
401
- await auth.api.registerSSOProvider({
402
- body: {
403
- issuer: server.issuer.url!,
404
- domain: "localhost.com",
405
- oidcConfig: {
406
- clientId: "test",
407
- clientSecret: "test",
408
- },
409
- providerId: "test-1",
410
- },
411
- headers,
412
- });
413
-
414
- await expect(
415
- auth.api.registerSSOProvider({
416
- body: {
417
- issuer: server.issuer.url!,
418
- domain: "localhost.com",
419
- oidcConfig: {
420
- clientId: "test",
421
- clientSecret: "test",
422
- },
423
- providerId: "test-2",
424
- },
425
- headers,
426
- }),
427
- ).rejects.toMatchObject({
428
- status: "FORBIDDEN",
429
- body: {
430
- message: "You have reached the maximum number of SSO providers",
431
- },
432
- });
433
- });
434
-
435
- it("should not allow creating a provider if limit from function is reached", async () => {
436
- const { auth, signInWithTestUser } = await getTestInstanceMemory({
437
- plugins: [sso({ providersLimit: async () => 1 })],
438
- });
439
- const { headers } = await signInWithTestUser();
440
-
441
- await auth.api.registerSSOProvider({
442
- body: {
443
- issuer: server.issuer.url!,
444
- domain: "localhost.com",
445
- oidcConfig: {
446
- clientId: "test",
447
- clientSecret: "test",
448
- },
449
- providerId: "test-1",
450
- },
451
- headers,
452
- });
453
338
 
454
- await expect(
455
- auth.api.registerSSOProvider({
456
- body: {
457
- issuer: server.issuer.url!,
458
- domain: "localhost.com",
459
- oidcConfig: {
460
- clientId: "test",
461
- clientSecret: "test",
462
- },
463
- providerId: "test-2",
464
- },
465
- headers,
466
- }),
467
- ).rejects.toMatchObject({
468
- status: "FORBIDDEN",
469
- body: {
470
- message: "You have reached the maximum number of SSO providers",
471
- },
472
- });
473
- });
474
339
  it("should not create user with SSO provider when sign ups are disabled", async () => {
475
- const res = await auth.api.signInSSO({
476
- body: {
477
- email: "my-email@localhost.com",
478
- callbackURL: "/dashboard",
340
+ const headers = new Headers();
341
+ const res = await authClient.signIn.sso({
342
+ email: "my-email@localhost.com",
343
+ callbackURL: "/dashboard",
344
+ fetchOptions: {
345
+ throw: true,
346
+ onSuccess: cookieSetter(headers),
479
347
  },
480
348
  });
481
349
  expect(res.url).toContain("http://localhost:8080/authorize");
482
350
  expect(res.url).toContain(
483
351
  "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
484
352
  );
485
- const headers = new Headers();
486
- const callbackURL = await simulateOAuthFlow(res.url, headers);
353
+ const { callbackURL } = await simulateOAuthFlow(res.url, headers);
487
354
  expect(callbackURL).toContain(
488
355
  "/api/auth/error/error?error=signup disabled",
489
356
  );
490
357
  });
491
358
 
492
359
  it("should create user with SSO provider when sign ups are disabled but sign up is requested", async () => {
493
- const res = await auth.api.signInSSO({
494
- body: {
495
- email: "my-email@localhost.com",
496
- callbackURL: "/dashboard",
497
- requestSignUp: true,
360
+ const headers = new Headers();
361
+ const res = await authClient.signIn.sso({
362
+ email: "my-email@localhost.com",
363
+ callbackURL: "/dashboard",
364
+ requestSignUp: true,
365
+ fetchOptions: {
366
+ throw: true,
367
+ onSuccess: cookieSetter(headers),
498
368
  },
499
369
  });
500
370
  expect(res.url).toContain("http://localhost:8080/authorize");
501
371
  expect(res.url).toContain(
502
372
  "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
503
373
  );
504
- const headers = new Headers();
505
- const callbackURL = await simulateOAuthFlow(res.url, headers);
374
+ const { callbackURL } = await simulateOAuthFlow(res.url, headers);
506
375
  expect(callbackURL).toContain("/dashboard");
507
376
  });
508
377
  });
509
378
 
510
379
  describe("provisioning", async (ctx) => {
511
- const { auth, signInWithTestUser, customFetchImpl } =
512
- await getTestInstanceMemory({
380
+ const { auth, signInWithTestUser, customFetchImpl, cookieSetter } =
381
+ await getTestInstance({
513
382
  plugins: [sso(), organization()],
514
383
  });
515
384
 
385
+ const authClient = createAuthClient({
386
+ plugins: [ssoClient()],
387
+ baseURL: "http://localhost:3000",
388
+ fetchOptions: {
389
+ customFetchImpl,
390
+ },
391
+ });
392
+
516
393
  beforeAll(async () => {
517
394
  await server.issuer.keys.generate("RS256");
518
395
  server.issuer.on;
@@ -540,12 +417,14 @@ describe("provisioning", async (ctx) => {
540
417
  if (!location) throw new Error("No redirect location found");
541
418
 
542
419
  let callbackURL = "";
420
+ const newHeaders = new Headers();
543
421
  await betterFetch(location, {
544
422
  method: "GET",
545
423
  customFetchImpl: fetchImpl || customFetchImpl,
546
424
  headers,
547
425
  onError(context) {
548
426
  callbackURL = context.response.headers.get("location") || "";
427
+ cookieSetter(newHeaders)(context);
549
428
  },
550
429
  });
551
430
 
@@ -605,18 +484,20 @@ describe("provisioning", async (ctx) => {
605
484
  expect(provider).toMatchObject({
606
485
  organizationId: organization?.id,
607
486
  });
608
-
609
- const res = await auth.api.signInSSO({
610
- body: {
611
- email: "my-email@localhost.com",
612
- callbackURL: "/dashboard",
487
+ const newHeaders = new Headers();
488
+ const res = await authClient.signIn.sso({
489
+ email: "my-email@localhost.com",
490
+ callbackURL: "/dashboard",
491
+ fetchOptions: {
492
+ onSuccess: cookieSetter(newHeaders),
493
+ throw: true,
613
494
  },
614
495
  });
615
496
  expect(res.url).toContain("http://localhost:8080/authorize");
616
497
  expect(res.url).toContain(
617
498
  "redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fsso%2Fcallback%2Ftest",
618
499
  );
619
- const newHeaders = new Headers();
500
+
620
501
  const callbackURL = await simulateOAuthFlow(res.url, newHeaders);
621
502
  expect(callbackURL).toContain("/dashboard");
622
503
  const org = await auth.api.getFullOrganization({
package/tsconfig.json CHANGED
@@ -5,10 +5,5 @@
5
5
  "outDir": "./dist",
6
6
  "lib": ["esnext", "dom", "dom.iterable"]
7
7
  },
8
- "references": [
9
- {
10
- "path": "../better-auth/tsconfig.json"
11
- }
12
- ],
13
8
  "include": ["src"]
14
9
  }