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.
/change-password
route#
Step 1: Creating the - 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
- NodeJS
- GoLang
- Python
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})
import ( "net/http"
"github.com/supertokens/supertokens-golang/recipe/session")
// the following example uses net/httpfunc main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { // Wrap the API handler in session.VerifySession session.VerifySession(nil, changePasswordAPI).ServeHTTP(rw, r) })}
func changePasswordAPI(w http.ResponseWriter, r *http.Request) { // TODO: see next steps}
# the following example uses flaskfrom supertokens_python.recipe.session.framework.flask import verify_sessionfrom flask import Flask
app = Flask(__name__)
@app.route('/change-password', methods=['POST']) @verify_session()def change_password(): pass # 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'suserId
. - Use the recipe's sign in function and check if the old password is valid
- Update the user's password.
- NodeJS
- GoLang
- Python
// the following example uses expressimport ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";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) => {
// 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 user's Id from the session let userId = session!.getUserId()
// get the signed in user's email from the getUserById function let userInfo = await ThirdPartyEmailPassword.getUserById(userId)
if (userInfo === undefined) { throw new Error("Should never come here") }
// call signin to check that input password is correct let isPasswordValid = await ThirdPartyEmailPassword.emailPasswordSignIn(userInfo.email, oldPassword)
if (isPasswordValid.status !== "OK") { // TODO: handle incorrect password error return }
// update the user's password using updateEmailOrPassword let response = await ThirdPartyEmailPassword.updateEmailOrPassword({ userId, password: updatedPassword }) // TODO: send successful password update response
})
import ( "encoding/json" "net/http"
"github.com/supertokens/supertokens-golang/recipe/session" "github.com/supertokens/supertokens-golang/recipe/thirdpartyemailpassword")
func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { // Wrap the API handler in session.VerifySession session.VerifySession(nil, changePasswordAPI).ServeHTTP(rw, r) })}
type RequestBody struct { OldPassword string NewPassword string}
func changePasswordAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below sessionContainer := session.GetSessionFromRequestContext(r.Context())
// retrive the old password from the request body var requestBody RequestBody err := json.NewDecoder(r.Body).Decode(&requestBody) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return }
// get the userId from the session userID := sessionContainer.GetUserID()
// get the signed in user's email from the getUserById function userInfo, err := thirdpartyemailpassword.GetUserById(userID) if err != nil { // TODO: Handle error return }
// call signin to check that the input is correct isPasswordValid, err := thirdpartyemailpassword.EmailPasswordSignIn(userInfo.Email, requestBody.OldPassword) if err != nil { // TODO: Handle error return }
if isPasswordValid.OK != nil { // TODO: Handle error return }
_, err = thirdpartyemailpassword.UpdateEmailOrPassword(userID, &userInfo.Email, &requestBody.NewPassword) if err != nil { // TODO: Handle error return } // TODO: send successful password update response
}
from supertokens_python.recipe.session.framework.flask import verify_sessionfrom supertokens_python.recipe.session import SessionContainerfrom supertokens_python.recipe.thirdpartyemailpassword.syncio import get_user_by_id, emailpassword_sign_in, update_email_or_passwordfrom supertokens_python.recipe.thirdpartyemailpassword.interfaces import EmailPasswordSignInWrongCredentialsErrorfrom flask import g
@app.route('/change-password', methods=['POST']) @verify_session()def change_password():
session: SessionContainer = g.supertokens # get the userId from the session object user_id = session.get_user_id()
# get the signed in user's email from the getUserById function users_info = get_user_by_id(user_id)
if users_info is None: raise Exception("Should never come here")
# call signin to check that the input password is correct isPasswordValid = emailpassword_sign_in(users_info.email, request.json["oldPassword"])
if isinstance(isPasswordValid, EmailPasswordSignInWrongCredentialsError): # TODO: handle incorrect password error return # update the users password update_email_or_password(user_id, password=request.json["newPassword"])
# TODO: send successful password update response
#
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.
- NodeJS
- GoLang
- Python
// the following example uses expressimport ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";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
})
import ( "net/http"
"github.com/supertokens/supertokens-golang/recipe/session")
func main() { _ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { // Wrap the API handler in session.VerifySession session.VerifySession(nil, changePasswordAPI).ServeHTTP(rw, r) })}
type ResponseBody struct { OldPassword string NewPassword string}
func changePasswordAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below sessionContainer := session.GetSessionFromRequestContext(r.Context()) userID := sessionContainer.GetUserID()
/** * * ... * see previous step * ... * * */
// revoke all sessions for the user _, err := session.RevokeAllSessionsForUser(userID) if err != nil { // TODO: Handle error }
// revoke the user's current session, we do this to remove the auth cookies, logging out the user on the frontend err = sessionContainer.RevokeSession() if err != nil { // TODO: Handle error }
// TODO: send successful password update response}
from supertokens_python.recipe.session.framework.flask import verify_sessionfrom supertokens_python.recipe.session.syncio import revoke_all_sessions_for_userfrom flask import Flaskfrom supertokens_python.recipe.session import SessionContainer
app = Flask(__name__)@app.route('/change-password', methods=['POST']) @verify_session()def change_password(): session: SessionContainer = g.supertokens # get the userId from the session object user_id = session.get_user_id()
# TODO: see previous step...
# revoke all sessions for the user revoke_all_sessions_for_user(user_id) # revoke the user's current session, we do this to remove the auth cookies, logging out the user on the frontend session.sync_revoke_session()
# TODO: send successful password update response