@@ -61,84 +61,91 @@ Call the endpoint from the authentication flow used by your legacy provider.
6161
6262
6363:::warning no-title
64- Auth0 does not export password hashes by default. You will have to contact their support and request them.
64+ Auth0 does not expose password hashes or ` TOTP ` device information.
65+ You will have to contact their support separately if you need this type of data.
6566:::
6667
6768##### 1. Access the Auth0 Dashboard
6869##### 2. From the navigation menu go to * Actions* > * Library*
6970##### 3. Click * Create Action* > * Create custom action*
70- ##### 4. Specify a custom name for your action and then select ** Login/Post Login* * as the trigger
71+ ##### 4. Specify a custom name for your action and then select * Login/Post Login* as the trigger
7172##### 5. After the action has been created, click the * Add Secret* button and save your ` SUPERTOKENS_CORE_API_KEY ` as a secret
7273##### 5. Paste the following code in the editor
7374
7475``` typescript
7576exports .onExecutePostLogin = async (event , api ) => {
7677 const SUPERTOKENS_CORE_URL = " <YOUR_SUPERTOKENS_CORE_URL>" ;
7778 const SUPERTOKENS_API_KEY = event .secrets .SUPERTOKENS_API_KEY ;
79+ const auth0User = event .user ;
7880
7981 try {
80- // Check if user already migrated
81- if (event .user .app_metadata ?.migrated_to_supertokens ) {
82- console .log (` User ${event .user .user_id } already migrated ` );
82+ if (auth0User .app_metadata ?.migrated_to_supertokens ) {
83+ console .log (` User ${auth0User .user_id } already migrated ` );
8384 return ;
8485 }
8586
86- const connectionStrategy = event .connection .strategy ;
87-
8887 const userPayload = {
89- externalUserId: event . user .user_id ,
88+ externalUserId: auth0User .user_id ,
9089 userMetadata: {
91- auth0_user_id: event .user .user_id ,
92- auth0_connection: event .connection .name ,
93- name: event .user .name ,
94- nickname: event .user .nickname ,
95- picture: event .user .picture
90+ auth0_user_id: auth0User .user_id ,
91+ name: auth0User .name ,
92+ nickname: auth0User .nickname ,
93+ picture: auth0User .picture
94+ auth0_user_metadata : auth0User .user_metadata ,
95+ auth0_app_metadata: auth0User .app_metadata
9696 },
97+ roles: auth0User .app_metadata ?.roles || [],
9798 loginMethods: []
9899 };
100+
101+ const ThirdPartyProviders = [' google-oauth2' , ' facebook' , ' github' , ' apple' ];
99102
100- // Handle different login methods
101- if (connectionStrategy === ' google-oauth2' || connectionStrategy === ' facebook' ||
102- connectionStrategy === ' github' || connectionStrategy === ' apple' ||
103- connectionStrategy .includes (' oauth' )) {
104- const provider = mapProvider (connectionStrategy );
105- const thirdPartyUserId = event .user .user_id .split (' |' )[1 ];
106-
107- userPayload .loginMethods .push ({
108- recipeId: " thirdparty" ,
109- thirdPartyId: provider ,
110- thirdPartyUserId: thirdPartyUserId ,
111- email: event .user .email ,
112- isVerified: event .user .email_verified || false ,
113- isPrimary: true ,
114- timeJoinedInMSSinceEpoch: new Date (event .user .created_at ).getTime ()
115- });
116-
117- } else if (connectionStrategy === ' auth0' || connectionStrategy === ' Username-Password-Authentication' ) {
118- // Auth0 does not export passworded hashes by default
119- // You will have to contact their support and request them
120- userPayload .loginMethods .push ({
121- recipeId: " emailpassword" ,
122- email: event .user .email ,
123- passwordHash: getPasswordHash (event .user .email ),
124- hashingAlgorithm: " bcrypt" ,
125- isVerified: event .user .email_verified || false ,
126- isPrimary: true ,
127- timeJoinedInMSSinceEpoch: new Date (event .user .created_at ).getTime ()
128- });
129- } else if (connectionStrategy === ' sms' || connectionStrategy === ' email' ) {
130- const isEmail = connectionStrategy === ' email' ;
131- userPayload .loginMethods .push ({
132- recipeId: " passwordless" ,
133- email: isEmail ? event .user .email : undefined ,
134- phoneNumber: ! isEmail ? event .user .phone_number : undefined ,
135- isVerified: true ,
136- isPrimary: true ,
137- timeJoinedInMSSinceEpoch: new Date (event .user .created_at ).getTime ()
138- });
139- }
103+ auth0User .identities .forEach ((identity , index ) => {
104+ if (ThirdPartyProviders .includes (identity .provider )) {
105+ userPayload .loginMethods .push ({
106+ recipeId: " thirdparty" ,
107+ thirdPartyId: mapProvider (identity .provider ),
108+ thirdPartyUserId: identity .user_id ,
109+ email: identity .profileData ?.email ?? auth0User .email ,
110+ isVerified: identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
111+ isPrimary: index === 0 ,
112+ timeJoinedInMSSinceEpoch: new Date (auth0User .created_at ).getTime ()
113+ });
114+ }
115+ } else if (identity .provider === ' auth0' || identity .provider === ' Username-Password-Authentication' ) {
116+ // Auth0 does not export passworded hashes by default
117+ // You will have to contact their support and request them
118+ userPayload.loginMethods.push({
119+ recipeId : " emailpassword" ,
120+ email : identity .profileData ?.email ?? auth0User .email ,
121+ // Request the password hash from Auth0 and then implement the function to retrieve the values
122+ passwordHash : getPasswordHash (identity .profileData ?.email ),
123+ hashingAlgorithm : " bcrypt" ,
124+ isVerified : identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
125+ isPrimary : index === 0 ,
126+ timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
127+ });
128+ } else if (identity .provider === ' sms' ) {
129+ userPayload.loginMethods.push({
130+ recipeId : " passwordless" ,
131+ phoneNumber : identity .profileData ?.phone_number ?? auth0User .phone_number ,
132+ isVerified : identity .profileData ?.phone_verified ?? auth0User .phone_verified ?? false ,
133+ isPrimary : index === 0 ,
134+ timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
135+ });
136+ } else if (identity .provider === ' email' ) {
137+ userPayload.loginMethods.push({
138+ recipeId : " passwordless" ,
139+ email : identity .profileData ?.email || auth0User .email ,
140+ isVerified : identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
141+ isPrimary : index === 0 ,
142+ timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
143+ });
144+ } else {
145+ throw new Error(` Uknown provider: ${identity .provider } ` );
146+ }
147+ });
140148
141- // Import user to SuperTokens
142149 const response = await fetch (` ${SUPERTOKENS_CORE_URL }/bulk-import/import ` , {
143150 method: ' POST' ,
144151 headers: {
@@ -169,8 +176,6 @@ function mapProvider(strategy) {
169176 ' facebook' : ' facebook' ,
170177 ' github' : ' github' ,
171178 ' apple' : ' apple' ,
172- ' windowslive' : ' microsoft' ,
173- ' linkedin' : ' linkedin'
174179 };
175180 return mapping [strategy ] || strategy ;
176181}
@@ -484,59 +489,85 @@ cat auth0_users.json | jq -s '.' > auth0_users_array.json
484489
485490#### 6. Transform the data to the SuperTokens format
486491
492+ :::warning no-title
493+ Auth0 does not expose password hashes or ` TOTP ` device information.
494+ You will have to contact their support separately if you need this type of data.
495+ :::
496+
487497``` typescript
488498const fs = require (' fs' );
489499
490500const auth0Users = JSON .parse (fs .readFileSync (' auth0_users_array.json' , ' utf8' ));
491501
492502const superTokensUsers = auth0Users .map (auth0User => {
493- const loginMethods = [];
503+ if (auth0User .user_metadata ?.migrated_to_supertokens ) {
504+ console .log (` User ${auth0User .user_id } already migrated ` );
505+ return ;
506+ }
494507
495- auth0User .identities .forEach (identity => {
496- if (identity .provider === ' auth0' ) {
508+ const userPayload = {
509+ externalUserId: event .user .user_id ,
510+ userMetadata: {
511+ auth0_user_id: auth0User .user_id ,
512+ name: auth0User .name ,
513+ nickname: auth0User .nickname ,
514+ picture: auth0User .picture ,
515+ auth0_user_metadata: auth0User .user_metadata
516+ auth0_app_metadata : auth0User .app_metadata
517+ },
518+ roles: auth0User .app_metadata ?.roles || [],
519+ loginMethods: [],
520+ };
521+
522+ const ThirdPartyProviders = [' google-oauth2' , ' facebook' , ' github' , ' apple' ];
523+
524+ auth0User .identities .forEach ((identity , index ) => {
525+ if (ThirdPartyProviders .includes (identity .provider )) {
526+ userPayload .loginMethods .push ({
527+ recipeId: " thirdparty" ,
528+ thirdPartyId: mapProvider (identity .provider ),
529+ thirdPartyUserId: identity .user_id ,
530+ email: identity .profileData ?.email ?? auth0User .email ,
531+ isVerified: identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
532+ isPrimary: index === 0 ,
533+ timeJoinedInMSSinceEpoch: new Date (auth0User .created_at ).getTime ()
534+ });
535+ }
536+ } else if (identity .provider === ' auth0' || identity .provider === ' Username-Password-Authentication' ) {
497537 // Auth0 does not export passworded hashes by default
498538 // You will have to contact their support and request them
499- loginMethods .push ({
539+ userPayload. loginMethods.push({
500540 recipeId : " emailpassword" ,
501- email: auth0User .email ,
502- passwordHash: getPasswordHash (auth0User .email ),
541+ email : identity .profileData ?.email ?? auth0User .email ,
542+ // Request the password hash from Auth0 and then implement the function to retrieve the values
543+ passwordHash : getPasswordHash (identity .profileData ?.email ),
503544 hashingAlgorithm : " bcrypt" ,
504- isVerified: auth0User .email_verified || false ,
505- isPrimary: true ,
506- timeJoinedInMSSinceEpoch: new Date (auth0User .created_at ).getTime ()
507- });
508- } else if ([' google-oauth2' , ' facebook' , ' github' , ' apple' ].includes (identity .provider )) {
509- loginMethods .push ({
510- recipeId: " thirdparty" ,
511- thirdPartyId: mapProvider (identity .provider ),
512- thirdPartyUserId: identity .user_id ,
513- email: auth0User .email ,
514- isVerified: auth0User .email_verified || false ,
515- isPrimary: true ,
545+ isVerified : identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
546+ isPrimary : index === 0 ,
516547 timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
517548 });
518549 } else if (identity .provider === ' sms' ) {
519- loginMethods .push ({
520- recipeId: " passwordless" ,
521- phoneNumber: auth0User .phone_number ,
522- isVerified: auth0User .phone_verified || false ,
523- isPrimary: true ,
524- timeJoinedInMSSinceEpoch: new Date (auth0User .created_at ).getTime ()
550+ userPayload. loginMethods.push({
551+ recipeId : " passwordless" ,
552+ phoneNumber : identity . profileData ?. phone_number || auth0User .phone_number ,
553+ isVerified : identity . profileData ?. phone_verified ?? auth0User .phone_verified ?? false ,
554+ isPrimary : index === 0 ,
555+ timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
525556 });
557+ } else if (identity .provider === ' email' ) {
558+ userPayload.loginMethods.push({
559+ recipeId : " passwordless" ,
560+ email : identity .profileData ?.email || auth0User .email ,
561+ isVerified : identity .profileData ?.email_verified ?? auth0User .email_verified ?? false ,
562+ isPrimary : index === 0 ,
563+ timeJoinedInMSSinceEpoch : new Date (auth0User .created_at ).getTime ()
564+ });
565+ } else {
566+ throw new Error(` Uknown provider: ${identity .provider } ` );
526567 }
527568 });
528569
529- return {
530- externalUserId: auth0User .user_id ,
531- userMetadata: {
532- auth0_user_id: auth0User .user_id ,
533- name: auth0User .name ,
534- nickname: auth0User .nickname ,
535- picture: auth0User .picture ,
536- ... auth0User .user_metadata
537- },
538- loginMethods: loginMethods
539- };
570+ return userPayload ;
540571});
541572
542573fs .writeFileSync (' supertokens_users.json' , JSON .stringify ({ users: superTokensUsers }, null , 2 ));
0 commit comments