How to delete entries (Cloud Code)

I'm wanting to use Cloud Code to delete player entries from all leaderboards as a part of a clean-up when deleting a player's account.

I've found the web API docs but I'm hoping to do it via Cloud Code so it's cleaner / easier.

I'm basing my code from the Leadboards with Cloud Code docs but I can't find any other API docs for unity-services/leaderboards-1.1 so I'm not sure what methods are available to me.

I want to do something like this

const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");

module.exports = async ({ params, context, logger }) => {
  const { projectId } = context;
  const { playerId } = params;
  const leaderboardsApi = new LeaderboardsApi(context);

  await leaderboardsApi.deletePlayerScoreAcrossAllLeaderboards(playerId);
  return { message: "ok" };
};

but obviously deletePlayerScoreAcrossAllLeaderboards isn't a valid method.

Hi Brogan89,

the functionality in question is not available as part of the Cloud Code Leaderboards SDK, but you can call the API endpoint directly using Axios as documented here. Keeping in mind that as an admin endpoint it has lower rate limits than the player endpoints, but hopefully for your use-case of deleting player's accounts that will be fine.

1 Like

Hey, cool thanks for the suggestion. I got most of the way there.
I'm getting auth issues though and I'm not sure why. I'm using serverToken, and the service account has "Leaderboards Admin" assigned to it.

The Cloud Code I'm using is

const axios = require("axios-0.21");

module.exports = async ({ params, context, logger }) => {

  logger.debug(context);

  const { projectId, environmentId, accessToken, serviceToken } = context;
  const { playerId } = params;

  let config = {
    headers: {
      Authorization: `Basic ${serviceToken}`
    }
  };

  let url = `https://services.api.unity.com/leaderboards/v1/projects/${projectId}/environments/${environmentId}/leaderboards/scores/players/${playerId}/purge`;
  let result = await axios.delete(url, config);
  return result.data;
};

And the response is (I've removed some IDs)

Invocation Error
------------------------------
Error: Request failed with status code 401

{
  "message": "Request failed with status code 401",
  "name": "Error",
  "request": {
    "headers": {
      "Accept": "application/json, text/plain, */*",
      "Authorization": "Basic <TOKEN>",
      "User-Agent": "axios/0.21.4"
    },
    "method": "delete",
    "url": "https://services.api.unity.com/leaderboards/v1/projects/<PROJ_ID>/environments/<ENV_ID>/leaderboards/scores/players/KuT0GYspN7sxOACPhkQFuniMTMaX/purge"
  },
  "response": {
    "code": 51,
    "detail": "Authentication Failed",
    "requestId": "f38bfcd8-ced9-4485-8447-e6a2a3ed7c14",
    "status": 401,
    "title": "Unauthorized",
    "type": "https://services.docs.unity.com/docs/errors#51"
  }
}

Not sure how I'm using the auth token wrong.

Hi Brogan89,

unfortunately the built-in Cloud Code auth tokens will not work with admin endpoints like that, apologies for not clarifying earlier. To call admin endpoints like the one in question from Cloud Code we will need to use Service Account authentication as documented here.

Service Account auth from within Cloud Code will involve the following steps:

  • Create a Service Account
  • Give it the "Leaderboards Admin" project role
  • Create a key for the Service Account and make a note of the key ID and secret
  • From within the Cloud Code script, pass in the Service Account credentials and use them with Basic auth in the request to Leaderboards instead of the Cloud Code service token

The following is your script with the addition of the token exchange mechanism. Alex has provided an example below where the Service Account key ID and secret are passed in as script parameters "saKeyId" and "saSecret" respectively, along with the player ID to be purged (though that can also be the player ID from the Cloud Code context).

Note that it is using the Axios auth config option which will automatically base64-encode and format the credentials as required for basic auth. Alternatively those can be formatted manually as outlined in the Service Account docs.

Hope this helps!

Looks like the leaderboard functions use basic auth. Here is a working script:

const axios = require("axios-0.21");
module.exports = async ({ params, context, logger }) => {
  logger.debug(context);
  const { playerId, projectId, environmentId, accessToken, serviceToken } = context;
  const { saKeyId, saSecret, playerIDToRemove } = params;
  let url = `https://services.api.unity.com/leaderboards/v1/projects/${projectId}/environments/${environmentId}/leaderboards/scores/players/${playerIDToRemove}/purge`;

  let result = await axios({
    method: 'DELETE',
    url: url,
    auth: {
      username: saKeyId,
      password: saSecret
    },
    headers: {
      'Content-Type': 'application/json',
    }
  });
  return result.data;
};
1 Like

Hi Alex,

thank for spotting that, I was looking at the wrong gateway when putting that together (endpoints on leaderboards.services.api.unity.com/v1 vs services.api.unity.com/leaderboards/v1). The use of the token exchange is indeed unnecessary for this use case and Service Account credentials can be used directly. My apologies for any confusion, and I've updated my post to reference your example for any other users coming to this thread.

1 Like


Worked a treat! Thanks