@turnkey/sdk-react 5.1.0 → 5.2.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/CHANGELOG.md CHANGED
@@ -1,9 +1,35 @@
1
1
  # @turnkey/sdk-react
2
2
 
3
+ ## 5.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @turnkey/crypto@2.4.0
9
+ - @turnkey/sdk-browser@5.2.1
10
+ - @turnkey/sdk-server@4.1.1
11
+ - @turnkey/wallet-stamper@1.0.4
12
+
13
+ ## 5.2.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#632](https://github.com/tkhq/sdk/pull/632) [`a38a6e3`](https://github.com/tkhq/sdk/commit/a38a6e36dc2bf9abdea64bc817d1cad95b8a289a) Author [@amircheikh](https://github.com/amircheikh) - Added optional `socialLinking` boolean to the `authConfig`. If true, this will enable social linking for new Google <-> Gmail users. For more information on social linking, visit [our docs](https://docs.turnkey.com/authentication/social-logins#social-linking).
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [[`5afbe51`](https://github.com/tkhq/sdk/commit/5afbe51949bdd1997fad083a4c1e4272ff7409dc), [`10ee5c5`](https://github.com/tkhq/sdk/commit/10ee5c524b477ce998e4fc635152cd101ae5a9cc), [`a38a6e3`](https://github.com/tkhq/sdk/commit/a38a6e36dc2bf9abdea64bc817d1cad95b8a289a), [`40c4035`](https://github.com/tkhq/sdk/commit/40c40359ec7096d0bca39ffc93e89361b3b11a1a), [`593de2d`](https://github.com/tkhq/sdk/commit/593de2d9404ec8cf53426f9cf832c13eefa3fbf2)]:
22
+ - @turnkey/sdk-browser@5.2.0
23
+ - @turnkey/wallet-stamper@1.0.4
24
+ - @turnkey/crypto@2.4.0
25
+ - @turnkey/sdk-server@4.1.0
26
+
3
27
  ## 5.1.0
4
28
 
5
29
  ### Minor Changes
6
30
 
31
+ - Update @turnkey/sdk-types readme and install dependency in packages with common types
32
+
7
33
  - [#650](https://github.com/tkhq/sdk/pull/650) [`27fe590`](https://github.com/tkhq/sdk/commit/27fe590cdc3eb6a8cde093eeefda2ee1cdc79412) Author [@turnekybc](https://github.com/turnekybc) - Update @turnkey/sdk-types readme and install dependency in packages with common types
8
34
 
9
35
  ### Patch Changes
package/README.md CHANGED
@@ -121,6 +121,7 @@ function AuthPage() {
121
121
  googleEnabled: true,
122
122
  appleEnabled: false,
123
123
  facebookEnabled: false,
124
+ socialLinking: true, // Enable social linking
124
125
  sessionLengthSeconds: 3600, //1 hour r/w session
125
126
  };
126
127
 
@@ -20,6 +20,7 @@ interface AuthProps {
20
20
  googleEnabled: boolean;
21
21
  walletEnabled: boolean;
22
22
  openOAuthInPage?: boolean;
23
+ socialLinking?: boolean;
23
24
  sessionLengthSeconds?: number;
24
25
  googleClientId?: string;
25
26
  appleClientId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../../src/components/auth/Auth.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAcnD,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI3E,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAoCD,UAAU,SAAS;IACjB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,UAAU,EAAE;QACV,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,YAAY,EAAE,OAAO,CAAC;QACtB,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,kBAAkB,CAAC,EAAE,eAAe,CAAC,4BAA4B,CAAC,CAAC;IACnE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,QAAA,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CA4pB7B,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../../src/components/auth/Auth.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAenD,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI3E,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAoCD,UAAU,SAAS;IACjB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,UAAU,EAAE;QACV,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,YAAY,EAAE,OAAO,CAAC;QACtB,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,kBAAkB,CAAC,EAAE,eAAe,CAAC,4BAA4B,CAAC,CAAC;IACnE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,QAAA,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAquB7B,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -7,6 +7,7 @@ var jsxRuntime = require('react/jsx-runtime');
7
7
  var Auth_module = require('./Auth.module.css.js');
8
8
  var React = require('react');
9
9
  var PhoneInput = require('./PhoneInput.js');
10
+ var jwtDecode = require('jwt-decode');
10
11
  var Google = require('./Google.js');
11
12
  var Apple = require('./Apple.js');
12
13
  var Facebook = require('./Facebook.js');
@@ -226,44 +227,97 @@ const Auth = ({
226
227
  }
227
228
  setLoading(undefined);
228
229
  };
229
- const handleOAuthLogin = async (credential, providerName) => {
230
+ const handleOAuthLogin = async (credential, providerName, socialLinking = false) => {
230
231
  const pubKey = await indexedDbClient?.getPublicKey();
231
232
  if (!pubKey) {
232
233
  return;
233
234
  }
234
235
  setOauthLoading(providerName);
235
- const createSuborgData = {
236
- oauthProviders: [{
237
- providerName,
238
- oidcToken: credential
239
- }]
236
+ const oauthProviders = [{
237
+ providerName,
238
+ oidcToken: credential
239
+ }];
240
+ let createSuborgData = {
241
+ oauthProviders,
242
+ ...(customAccounts && {
243
+ customAccounts
244
+ })
240
245
  };
241
- if (customAccounts) {
242
- createSuborgData.customAccounts = customAccounts;
243
- }
244
- const resp = await sdkServer.server.getOrCreateSuborg({
245
- filterType: constants.FilterType.OidcToken,
246
- filterValue: credential,
247
- additionalData: createSuborgData
248
- });
249
- const suborgIds = resp?.subOrganizationIds;
250
- if (!suborgIds || suborgIds.length === 0) {
246
+ const completeLogin = async suborgID => {
247
+ const sessionResponse = await sdkServer.server.oauthLogin({
248
+ suborgID,
249
+ oidcToken: credential,
250
+ publicKey: pubKey,
251
+ sessionLengthSeconds: authConfig.sessionLengthSeconds
252
+ });
253
+ if (sessionResponse?.session) {
254
+ await indexedDbClient.loginWithSession(sessionResponse.session);
255
+ return onAuthSuccess();
256
+ }
251
257
  onError(constants.authErrors.oauth.loginFailed);
252
- return;
258
+ };
259
+ // Non-social-linking path: getOrCreateSuborg then login
260
+ if (!socialLinking) {
261
+ const resp = await sdkServer.server.getOrCreateSuborg({
262
+ filterType: constants.FilterType.OidcToken,
263
+ filterValue: credential,
264
+ additionalData: createSuborgData
265
+ });
266
+ const suborgIds = resp?.subOrganizationIds;
267
+ if (!suborgIds?.length) {
268
+ return onError(constants.authErrors.oauth.loginFailed);
269
+ }
270
+ return completeLogin(suborgIds[0]);
253
271
  }
254
- const suborgId = suborgIds[0];
255
- const sessionResponse = await sdkServer.server.oauthLogin({
256
- suborgID: suborgId,
257
- oidcToken: credential,
258
- publicKey: pubKey,
259
- sessionLengthSeconds: authConfig.sessionLengthSeconds
260
- });
261
- if (sessionResponse && sessionResponse.session) {
262
- await indexedDbClient.loginWithSession(sessionResponse.session);
263
- await onAuthSuccess();
264
- } else {
265
- onError(constants.authErrors.oauth.loginFailed);
272
+ // Social-linking path
273
+ // See if there's already a suborg tied to this token
274
+ const oidcOrgIds = (await sdkServer.server.getSuborgs({
275
+ filterType: constants.FilterType.OidcToken,
276
+ filterValue: credential
277
+ }))?.organizationIds;
278
+ let orgId = oidcOrgIds?.[0];
279
+ // If not, try to link by verified email (Google only)
280
+ if (!orgId) {
281
+ const {
282
+ email: oidcEmail,
283
+ iss
284
+ } = jwtDecode.jwtDecode(credential) || {};
285
+ createSuborgData = {
286
+ email: oidcEmail,
287
+ oauthProviders,
288
+ ...(customAccounts && {
289
+ customAccounts
290
+ })
291
+ };
292
+ if (oidcEmail && iss === "https://accounts.google.com") {
293
+ const emailOrgIds = (await sdkServer.server.getVerifiedSuborgs({
294
+ filterType: constants.FilterType.Email,
295
+ filterValue: oidcEmail
296
+ }))?.organizationIds;
297
+ if (emailOrgIds?.[0]) {
298
+ orgId = emailOrgIds[0];
299
+ // attach this new OIDC provider to the existing user
300
+ const userId = (await sdkServer.server.getUsers({
301
+ organizationId: orgId
302
+ }))?.users?.[0]?.userId;
303
+ if (!userId) {
304
+ return onError(constants.authErrors.oauth.loginFailed);
305
+ }
306
+ await sdkServer.server.createOauthProviders({
307
+ organizationId: orgId,
308
+ userId,
309
+ oauthProviders
310
+ });
311
+ } else {
312
+ // No orgs with the email. Create brand new suborg
313
+ orgId = (await sdkServer.server.createSuborg(createSuborgData))?.subOrganizationId;
314
+ }
315
+ } else {
316
+ // Non-Google or no email in OIDC. Create new suborg
317
+ orgId = (await sdkServer.server.createSuborg(createSuborgData))?.subOrganizationId;
318
+ }
266
319
  }
320
+ return orgId ? completeLogin(orgId) : onError(constants.authErrors.oauth.loginFailed);
267
321
  };
268
322
  const handleLoginWithWallet = async () => {
269
323
  setLoading("wallet");
@@ -341,17 +395,17 @@ const Auth = ({
341
395
  layout: layout,
342
396
  clientId: authConfig.googleClientId ?? process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
343
397
  openInPage: authConfig.openOAuthInPage,
344
- onSuccess: response => handleOAuthLogin(response.idToken, "Google")
398
+ onSuccess: response => handleOAuthLogin(response.idToken, "Google", authConfig.socialLinking)
345
399
  }), appleEnabled && jsxRuntime.jsx(Apple.default, {
346
400
  layout: layout,
347
401
  clientId: authConfig.appleClientId ?? process.env.NEXT_PUBLIC_APPLE_CLIENT_ID,
348
402
  openInPage: authConfig.openOAuthInPage,
349
- onSuccess: response => handleOAuthLogin(response.idToken, "Apple")
403
+ onSuccess: response => handleOAuthLogin(response.idToken, "Apple") // No need to pass socialLinking for Apple. It's not supported
350
404
  }), facebookEnabled && jsxRuntime.jsx(Facebook.default, {
351
405
  layout: layout,
352
406
  clientId: authConfig.facebookClientId ?? process.env.NEXT_PUBLIC_FACEBOOK_CLIENT_ID,
353
407
  openInPage: authConfig.openOAuthInPage,
354
- onSuccess: response => handleOAuthLogin(response.id_token, "Facebook")
408
+ onSuccess: response => handleOAuthLogin(response.id_token, "Facebook") // No need to pass socialLinking for Facebook. It's not supported
355
409
  })]
356
410
  });
357
411
  };