User Password Change Using Game Data Service

Introduction

If one of your users loses or forgets their password, you'll want an automated way for them to retrieve it.

This tutorial shows you how to set up Cloud Code to do this. The set up described here is the most basic way users have access to your platform without them having to be authenticated and can be developed for more advanced and specific applications.

Game Data Service? This tutorial assumes an understanding of the Game Data Service. We strongly recommend that you review the Game Data and the Data Explorer topics before you attempt to follow this tutorial.

Cloud Code Section

Choosing Our Sequence of Actions and Passing in scriptData

1. Navigate to the Configurator > Cloud Code.

2. Under Scripts click to expand the Requests area and then select AuthenticationRequest. The Cloud Code editor opens for the request and you can start editing it. This will allow users to run the password recovery logic without having an authenticated account.

var status = "Started";
//Checking if there is any scriptData passed in, if not then carry on the authentication as normal
if(Spark.data.scriptData){

    var action = Spark.data.scriptData.action;

    if("passwordRecoveryRequest" === action){
        //Start recovery sequence
        startRecovery(Spark.data.scriptData);

    } else if ("resetPassword" === action){
        //Start reset sequence
        resetPassword(Spark.data.scriptData);
    }

    else
    {
        // action variable isn't valid, check spelling or value
        status = "invalid action";
    }
// set an error to prevent the AuthenticationRequest being processed
    Spark.setScriptError("action", status);

}

Linking User Account to E-Mail

Next, you'll need to link the user account to an E-mail. You can do this:

If the email passed in is linked to an account, then:

Below is an example of how to save Emails on users and keep track of them so you can generate and send users tokens to change their passwords with. For this to work:

The Request Cloud Code:

if(Spark.getData().scriptData.email == null){
    Spark.setScriptError("ERROR", "Email not specified");
} else{

    //Load API
    var API = Spark.getGameDataService();

    //Email
    var email = Spark.getData().scriptData.email;

    //Create condition
    var query = API.S("email").eq(email);

    //Check for results
    var resultOBJ = API.queryItems("playerProfile", query);

    //Check for errors
    if(resultOBJ.error()){
        Spark.setScriptError("ERROR", resultOBJ.error());

    } else{
        //Get result
        var result = resultOBJ.cursor();

        //If there's a result, means email is in use
        if(result.hasNext()){
            Spark.setScriptError("ERROR", "Email in use!")
        } else{
            Spark.setScriptData("email", Spark.getData().scriptData.email);
        }

    }
}

The Response Cloud Code:

if(!Spark.hasScriptErrors()){
//Load API
var API = Spark.getGameDataService();

//Create player inventory
doc = API.createItem("playerProfile", Spark.getPlayer().getPlayerId());
//Get Data
var data = doc.getData();

//Save userName and password
data.userName = Spark.getPlayer().getUserName();
data.displayName = Spark.getPlayer().getDisplayName();
data.email = Spark.getData().scriptData.email;

//Persist document
var status = doc.persistor().persist().error();

//Check if document saved
if(status){
    //return error if persistence interrupted
    Spark.setScriptError("ERROR", status)
}
}

Sending the Request from Test Harness or the SDK:

{
  "@class": ".RegistrationRequest",
  "displayName": "testUser",
  "password": "password",
  "userName": "testUser",
  "scriptData":{"email":"test@test.com"}
}

Below is an example code of how to create a system that saves emails and generates token for password recovery:

Sequence Picker

Depending on the 'action' scriptData input, we're going to decide the sequence the script is going to follow.

var status = "Started";
//Checking if there is any scriptData passed in, if not then carry on the authentication as normal
if(Spark.data.scriptData != null){

    var action = Spark.data.scriptData.action;

    if("passwordRecoveryRequest" === action){
        //Start recovery sequence
        startRecovery(Spark.data.scriptData);

    } else if ("resetPassword" === action){
        //Start reset sequence
        resetPassword(Spark.data.scriptData);
    }

    else
    {
        // action variable isn't valid, check spelling or value
        status = "invalid action";
    }
    //set an error to prevent the AuthenticationRequest being processed
    Spark.setScriptError("action", status);

}

Token Generation

This is our example of a token generating function. Yours could be anything you want it to be as long it's not easy to guess.

function generateRecoveryToken(){
    // this should be cryptographically strong, not simply date-based
    var key = "MySecretKey";
    var data = "ResetToken_" + new Date().getTime() + "_" + Math.random();
    var token = Spark.getDigester().hmacSha256Base64(key, data);

    return token;

}

Sending Out the E-Mail

We have full integration with SendGrid services. If you plan to use it to send your E-Mails, then create an account with them and wait for their E-Mail confirming that: "Your SendGrid account has been provisioned!", which then allows you to start sending emails. It might take up to 24 hours to receive it. You'll need:

function sendRecoveryEmail(email, name , token){
    //Here we use sendGrid as an example because we have full integration with their services.
    var myGrid = Spark.sendGrid("Username", "Password");
    //The email to send the message to and the name of the user
    myGrid.addTo( email , name );
    //Here you'd leave your organization or personal email
    myGrid.setFrom("Email", "Name");
    //The subject of your email
    myGrid.setSubject("Subject");
    // The body and message of your email, here we just send the token
    myGrid.setText(token);
    //Finally send the email
    myGrid.send();
}

If you don't want to use sendGrid you can use SparkHTTP to use your own provider.

Password Recovery Sequence

The password recovery sequence is going to generate a token, save it on the playerProfile Data Type, and send the player an email with a token.

function startRecovery(request){
    if(!request.email){
        //Either the email variable was not passed in or it was spelt incorrectly
        status = "email variable not passed in";
        return;
    }

    //Get data service
    var api = Spark.getGameDataService();

    //Construct query
    var query = api.S("email").eq(request.email);

    //Attempt to get results
    var resultOBJ = api.queryItems("playerProfile", query)


    //Check for errors
    if(resultOBJ.error()){
        status = "invalid";
        return;
    }else{
        //Get document
        var result = resultOBJ.cursor().next();
    }

    //Check for error
    if(result == null){
        status = "invalid";
        return;
    }


    // Function to generate a unique token
    var token = generateRecoveryToken();
    var player = Spark.loadPlayer( result.getId());

    //Sends the token back with the response
    Spark.setScriptData("token", token)

    //Get data object and insert new token
    var data = result.getData();
    data.token = token;

    //Persist doc and save potential error
    var serviceStatus = result.persistor().persist().error();

    //Check for errors
    if(serviceStatus){
        status = "invalid";
        return;
    }else{
         // Function used to send email
         sendRecoveryEmail(request.email, player.getDisplayName(), token);
        // Successfully found player and attempted to send email
        status = "complete";
    }

}

Password Reset Sequence

Finally, you have the password reset function, which takes a token and password parameter and checks to see if the Token is linked to an account. If it is, then it sets the password of that account to the new password passed in.

function resetPassword(request){
    if(!request.token || !request.password){
        status = "Password or token variable not passed in";
        return;
    }
    //Get data service
    var api = Spark.getGameDataService();

    //Construct query
    var query = api.S("token").eq(request.token);

    //Attempt to get results
    var resultOBJ = api.queryItems("playerProfile", query);


    //Check for errors
    if(resultOBJ.error()){
        status = "invalid";
        return;
    }else{
        var result = resultOBJ.cursor().next();
    }

    //Check if any results came back
    if(result == null){
        status = "invalid";
        return;
    }

    //Load data and player
    var player = Spark.loadPlayer(result.getId());
    var data = result.getData();

    //Set the token to null so it wont be used again
    data.token = null;

    //Persist entry
    var serviceStatus = result.persistor().persist().error();

    //Check for error
    if(serviceStatus){
        status = "invalid";
        return;
    }else{
         //Change password
        player.setPassword(request.password);
        //Unlock player just in case too many failed attempts were tried and player was locked
        player.unlock();
        status = "complete";
    }

}

Changing Password Using The SDK

Sending E-Mail

For this step you'll have to allow the user to input their e-mail:

Changing Password

After the player has been sent a token, they'll want to be able to change their password:

Did this page help you? Please enter your feedback below. For questions about using this part of the platform, please contact support here