Skip to main content

Allow users to change their passwords

caution

SuperTokens does not provide the UI for users to change/update their password, you will need to create the UI and setup a route on your backend to have this functionality.

In this section we will go over how you can create a route on your backend which can update a user's password. Calling this route will check if the old password is valid and update the user's profile with the new password.

Step 1: Creating the /change-password route#

  • You will need to create a route on your backend which is protected by the session verification middleware, this will ensure that only a authenticated user can access the protected route.
  • To learn more about how to use the session verfication middleware for other frameworks click here
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express"
import express from "express";

let app = express();

app.post("/change-password", verifySession(), async (req: SessionRequest, res: express.Response) => {
// TODO: see next steps
})

Step 2: Validate and update the user's password#

  • You can now use session object to retrive the logged in user's userId.
  • Use the recipe's sign in function and check if the old password is valid
  • Update the user's password.
// the following example uses express
import EmailPassword from "supertokens-node/recipe/emailpassword";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express"
import express from "express";
import supertokens from "supertokens-node";

let app = express();

app.post("/change-password", verifySession(), async (req: SessionRequest, res: express.Response) => {
// get the supertokens session object from the req
let session = req.session

// retrive the old password from the request body
let oldPassword = req.body.oldPassword

// retrive the new password from the request body
let updatedPassword = req.body.newPassword

// get the signed in user's email from the getUserById function
let userInfo = await supertokens.getUser(session!.getUserId())

if (userInfo === undefined) {
throw new Error("Should never come here")
}

let loginMethod = userInfo.loginMethods.find((lM) => lM.recipeUserId.getAsString() === session!.getRecipeUserId().getAsString() && lM.recipeId === "emailpassword");
if (loginMethod === undefined) {
throw new Error("Should never come here")
}
const email = loginMethod.email!;

// call signin to check that input password is correct
let isPasswordValid = await EmailPassword.verifyCredentials(session!.getTenantId(), email, oldPassword)

if (isPasswordValid.status !== "OK") {
// TODO: handle incorrect password error
return
}


// update the user's password using updateEmailOrPassword
let response = await EmailPassword.updateEmailOrPassword({
recipeUserId: session!.getRecipeUserId(),
password: updatedPassword,
tenantIdForPasswordPolicy: session!.getTenantId()
})

if (response.status === "PASSWORD_POLICY_VIOLATED_ERROR") {
// TODO: handle incorrect password error
return
}

// TODO: send successful password update response

})

Multi Tenancy

Notice that we pass in the tenantId as an argument to the signIn and the updateEmailOrPassword functions. This is because the we want to ensure that the current tenant has email password enabled, and we want to make sure that the we user's new password matches the password policy defined for their tenant (if you have defined different password polocies for different tenants).

If this user is shared across several tenants, their password is changed for all tenants.

Step 3: Revoke all sessions associated with the user (optional)#

  • Revoking all sessions associated with the user will force them to reauthenticate with their new password.
// the following example uses express
import EmailPassword from "supertokens-node/recipe/emailpassword";
import Session from "supertokens-node/recipe/session";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express"
import express from "express";

let app = express();

app.post("/change-password", verifySession(), async (req: SessionRequest, res: express.Response) => {

let userId = req.session!.getUserId();

/**
*
* ...
* see previous step
* ...
*
* */

// revoke all sessions for the user
await Session.revokeAllSessionsForUser(userId)

// revoke the current user's session, we do this to remove the auth cookies, logging out the user on the frontend.
await req.session!.revokeSession()

// TODO: send successful password update response

})