n1ru4l
09/09/2022, 9:31 AMgetUsersByEmail
2. Do a RPC call to our services/auth0 for checking whether an email/password user with a given email exists
3. if he does not exist use originalImplementation.emailPasswordSignUp
for creating the user with a random password
4. return that newly created user from the getUsersByEmail
function
I think one problem here is that getUsersByEmail
is not exclusively used by the reset password functionality - I can observe that function being called for a basic login attempt as well. 🤔
As I workaround I figured out that using the userContext
might work - though it seems a bit like an hacky attempt.
...
async getUsersByEmail(input) {
// In case this does not happen as part of the reset password token flow we just use the default implementation.
if (
input.userContext?.['_default']?.['request']?.['original']?.['url'] !==
'/api/auth/user/password/reset/token'
) {
return originalImplementation.getUsersByEmail(input);
}
...
Does that seem reasonable? Are there any better alternatives? Did anyone do something similar before?kelchy2714
09/09/2022, 9:56 AMn1ru4l
09/09/2022, 9:57 AMkelchy2714
09/09/2022, 10:00 AMrp_st
09/09/2022, 10:00 AMn1ru4l
09/09/2022, 10:01 AMrp_st
09/09/2022, 10:07 AMrp_st
09/09/2022, 10:09 AMn1ru4l
09/09/2022, 10:09 AMsupertokens-node
n1ru4l
09/09/2022, 10:10 AMasync getUsersByEmail(input) {
// In case this does not happen as part of the reset password token flow we just use the default implementation.
if (
// This is the original http request :)
input.userContext?.['_default']?.['request']?.['original']?.['url'] !==
'/api/auth/user/password/reset/token'
) {
return originalImplementation.getUsersByEmail(input);
}
// We first use the existing implementation for looking for users within supertokens.
const users = await originalImplementation.getUsersByEmail(input);
// If there is no email/password SuperTokens user yet, we need to check if there is an Auth0 user for this email.
if (users.some(user => user.thirdParty == null) === false) {
// RPC call to check if email/password user exists in Auth0
const dbUser = await checkWhetherAuth0EmailUserExists(config, { email: input.email });
if (dbUser) {
// If we have this user within our database we create our new supertokens user
const newUserResult = await originalImplementation.emailPasswordSignUp({
email: dbUser.email,
password: await generateRandomPassword(),
userContext: input.userContext,
});
if (newUserResult.status !== 'OK') {
return users;
}
// link the db record to the new supertokens user
await setUserIdMapping(config, {
auth0UserId: dbUser.auth0UserId,
supertokensUserId: newUserResult.user.id,
});
// return the new user so he is used for the password reset.
return [newUserResult.user];
}
}
return users;
},
rp_st
09/09/2022, 10:15 AMts
EmailPassword.init({
override: {
apis: (oI) => {
return {
...oI,
generatePasswordResetTokenPOST: async function (input) {
let email = input.formFields.find(i => i.id === "email");
// TODO: logic here to check if email exists in supertokens
// or in auth0 and create a user based on this email if needed
return oI.generatePasswordResetTokenPOST!(input);
}
}
}
}
})
n1ru4l
09/09/2022, 10:24 AMfunctions
originalImplementation, as it is a different scope 🤔 Any pointers on how to use them regardless of that? Should I just use the static methods on the singleton? e.g. ThirdPartyEmailPasswordNode.getUsersByEmail(email)
?rp_st
09/09/2022, 10:25 AMrp_st
09/09/2022, 10:25 AMn1ru4l
09/09/2022, 10:44 AMrp_st
09/09/2022, 10:45 AMn1ru4l
09/09/2022, 10:46 AMpasswordReset
. Tinkering within apis generatePasswordResetTokenPOST
feels a bit dangerous, but in the end it works 🙂rp_st
09/09/2022, 10:46 AMn1ru4l
09/09/2022, 10:47 AMn1ru4l
09/09/2022, 10:48 AMresolvePasswordResetUser
could fit in there, but I can also understand that adding to much overrides might become to convoluted at some pointrp_st
09/09/2022, 10:48 AMn1ru4l
09/09/2022, 10:57 AM