I’m trying to implement password reset in my iOS app. Upon user request, I call the following (Swift) code in the app:
let realmApp = App(id: REALM_ID)
realmApp.emailPasswordAuth.callResetPasswordFunction(email: "emailEnteredByUser", password: "password", args: [], completion)
My password reset function is the following:
exports = async function({ token, tokenId, username, password }) {
const ses = context.services.get('AmazonSES').ses("us-east-2");
const link = `https://.../reset_password?lang=en&token=${token}&tokenId=${tokenId}`;
// send custom email with link using Amazon SES
const result = await ses.SendTemplatedEmail({...});
return { status: 'pending' };
};
I don’t use the password sent by the app (which I literally fill with "password"
) for security reasons, because I have no way to authenticate the user.
The link to my website points to a JS script that looks like this:
// get parameters
const params = new URLSearchParams(window.location.search);
const lang = params.get("lang");
const token = params.get("token");
const tokenId = params.get("tokenId");
const passwordField = document.getElementById("fpassword");
[...]
function confirmButtonWasClicked() {
const app = new Realm.App({ id: REALM_ID });
app.emailPasswordAuth.resetPassword(passwordField.value, token, tokenId).then(
(value) => {
success();
},
(error) => {
failure();
}
);
}
The problem is, I get the following error every single time I try to reset the password:
Request failed (POST https://stitch.mongodb.com/api/client/v2.0/app/REALM_ID/auth/providers/local-userpass/reset): invalid token data (status 400)
I’m using:
RealmSwift v10.7.2
Realm-web@1.2.0 (https://unpkg.com/realm-web@1.2.0/dist/bundle.iife.js
)
I think the arguments to the resetPassword function should be token, tokenId and password
resetPassword(token, tokenId, passwordField.value)
Though in my case, even when I’m using the above sequence, I have the same issue which lead me to this thread. I’m using the same flow as the one you have.
My question is, why there is a need to send password to the callResetPasswordFunction when what we are doing is only sending a email via this function and actual ‘reseting the password’ is happening by calling resetPassword function. Perhaps, we are doing something wrong?
@Anuj_Dhingra I wondered the same thing. Perhaps someone from MongoDB can clarify that?
I’m still having this problem and it’s blocking my next release…
I tried manually calling the resetPassword
function from a NodeJS script and it didn’t work either.
I tried manually calling the resetPassword
function from the client iOS app and it worked.
So I had the hypothesis that the same client app needed to call both callResetPasswordFunction
and resetPassword
. So I made the following JS script:
const Realm = require("realm");
const appID = "appID";
const app = new Realm.App({ id: appID, timeout: 10000 });
const tokenId = "someTokenID";
const token = "someToken";
app.emailPasswordAuth.callResetPasswordFunction("someUserEmail", "password", []).then(
(value) => {
console.log("SUCCESS");
},
(error) => {
console.log(error);
}
);
// app.emailPasswordAuth.resetPassword("password", token, tokenId).then(
// (value) => {
// console.log("SUCCESS");
// },
// (error) => {
// console.log(token);
// console.log(tokenId);
// console.log(error);
// }
// );
Basically, I call the script once to send the reset password email, then I copy paste the token
and tokenId
I receive in the email, switch the commented code in the script, and run it again to reset the password.
It doesn’t work.
This seems like a bug in the NodeJS driver. I’m going to file a bug.
There seems to be a security hole in the ‘realm-web’ SDK with the resetPassword function.
The initial “newPassword” value that you enter in app.emailPasswordAuth.callResetPasswordFunction(email, newPassword) doesn’t matter when you confirm it with app.emailPasswordAuth.resetPassword(token, tokenId, newPassword)
What I really mean is that you can enter any value for password in app.emailPasswordAuth.resetPassword(token, tokenId, newPassword) and the realm-web SDK confirms the password change like the following.
app.emailPasswordAuth.callResetPasswordFunction(email, "123Apple#")
app.emailPasswordAuth.resetPassword(token, token_id, "CrazyBug99")
Running that code through the reset password function will actually confirm the password change when it clearly shouldn’t as “123Apple#” is different from “CrazyBug99” (assuming we extracted the right token and tokenId)