How to integrate the Web Playable with your website-level login

Put your webgame on your website with your own website authentication.

This assumes you have already completed (or understand) the game-level authentication part, independent of this website-level authentication.

Before reading the how-to implementation guide, these two articles can give you an overview of how it works:

Article: Authentication for Game Developers

Article: Authentication for Headless Web Gaming Destinations

📘

Summary of steps to integrate website-level user system with Pley.

To start the game on the web:

  • Call Pley's API issue-access-token HTTP API to get an access token.
  • Initialize the Pley Web SDK on the website, including the callback to issue new Access Tokens.
  • If the user is not logged in, initialize the Pley Web SDK without an access token to start a guest session.
  • Create the Web Playable using pley.createPlayable (Read more).
  • Update the session's authentication status (pley.updateToken) if the user logs-in or logs-out.
  • Implement a webhook e.g. POST /allocate-game-user to let Pley know which Pley Game User ID to load for the session.
  • Create a new Pley Game User if it's a guest who hasn't played on web before. (API Reference)

Terminology

TermDefintion
ScopeOne or more games using the same authentication system, such as YourStudioID.
Scope UserA user on your website ('scope')
Game UserA user in the backend of one of the games
Pley Access TokenA token certifying ownership of a certain Scope User (alive for 30 minutes)
Pley Game UserPley’s equivalent to your Game User for storing Pley-related features
Guest SessionA session where the user is not logged in, which is created by not issuing an access token.
Adopting progressWhen a guest user signs up or logs in to an account without progress for a game, that scope user should be assigned the Pley game user. The user will continue to play with their progress, but in a logged-in state.

Website setup

Issuing Pley Access Tokens

On your website, your account system is at the top level and determines which game progress is loaded when a user (Scope User) starts playing a game. To find the corresponding data on our side, Pley needs to stay in sync with which user is logged in. This is achieved by calling the Pley Issue Access Token endpoint using your Scope User ID and email (if available), which issues a Pley Access Token.

  1. The player clicks "Start Game".
  2. Call Pley's Issue Access Token endpoint and provide the user's ID and email.
  3. Receive Access Token in the response.
POST https://api.pley.com/v3/auth-kit/issue-access-token

// Authorization: Bearer API_TOKEN

// Body
{
  // Scope ID for game manager
  "scope_id": "xyz",
  // An ID of one of your scope users
  "scope_user_id": "xyz",
  // Email of the user
  "email": "[email protected]",
  // (Optional) Omit if you are using pley guest user feature
  "is_guest": false,
}

// Response
// 200
{
  "data": {
    // Pley Access Token
    "access_token": "xyz"
  }
}

Pley Web SDK

Pley provides the Pley Web SDK for your website to interface with Pley.

Article: Adding the Pley Web SDK to your website and initializing a web playable.

Adding Web SDK to your website

The Pley Web SDK script is hosted under https://www.pley.com/playable/v1/web_sdk.js.

Example:

<!DOCTYPE html>
<!-- Included in header -->
<head>
  <script src="https://www.pley.com/playable/v1/web_sdk.js"></script>
</head>
<body>
  <!-- Or loaded asynchronously in body -->
  <script>
    var script = document.createElement("script");
    script.src = "https://www.pley.com/playable/v1/web_sdk.js";
    script.async = true;
    script.onload = function() {
      const webSdk = new window.Pley.Web({
        // ...
      });
      // ...
    };
    document.body.appendChild(script);
  </script>
</body>

Web SDK Initialization with Initial Access Token

When initializing the Pley Web SDK, pass an access token as initialToken. If the user is currently not logged in, pass undefined (creating a guest session). Because the Pley Access Token is short-lived, it needs to be continually reissued. If a new token is needed, the onIssueToken callback will fire, which you should use to make a call to your backend to fetch a new Pley Access Token.

  1. Initialize the Pley Web SDK with the initial Access Token.
  2. When callback onIssueToken fires, call your backend to fetch a new Pley Access Token using Issue Access Token.
// Example implementation
async function issueToken(): string {
	if (!isLoggedIn) {
		return undefined;
	}
  const resp = await fetch("https://your-back-end.tech/v5/issue-pley-access-token");
  const token = await res.json();
  return token["access_token"];
}

const pley = new Pley.Web({
	scopeID: "ID_FROM_GAME_MANAGER",
	initialToken?: "xyz" | undefined,
	onIssueToken: issueToken,
})

Guest Sessions

Enabling guest sessions (playing the game without logging in) is simple.

  1. Initialize the Web SDK without an access token.
  2. If the user logs in, run pley.updateToken (see below).

Pley handles the rest.

Update token

When the user decides to log in, change accounts, log out, or the logged-in Scope User ID changes for any reason, the Pley Web SDK must be notified to take appropriate actions, such as closing game or payment sessions. When that happens, issue a new Pley Access Token or pass undefined to pley.updateToken() if the user is a guest.

// User session changed
pley.updateToken(token | undefined);

Connecting website-level login with game progress

The Allocate Game User webhook lets Pley start the game as the correct Game User when they are logged (https://docs.pley.com/reference/allocate-game-user). The webhook takes care of a few use cases:

Article: How should the authentication webhook work?

Handling the four authentication cases

The webhook implementation needs to follow this logic (in this order):

  1. Return existing web progress If the Scope User already has a Game User with a pley_game_user_id, return that ID. Use case: The user is logged in and has prior progress on the web.
  2. Return existing non-web progress If the Scope User has a Game User but no pley_game_user_id, assign new_pley_game_user_id to it and return that ID. Use case: The user has prior progress but has never played on the web.
  3. Adopt guest progress If the above cases matched no game user, the user might be a guest and the unlinked_pley_game_user_id may be set.
  • Look up a Game User with the pley_game_user_id matching unlinked_pley_game_user_id.
  • If not found, create a new Game User and assign unlinked_pley_game_user_id.
  • In either case, assign scope_user_id to the Game User and return unlinked_pley_game_user_id. Use case: The user played as a guest before logging in.
  1. Create new player If no existing progress is found, create a new Game User with both scope_user_id and new_pley_game_user_id, then return new_pley_game_user_id. Use case: The user is completely new to the game.

This is an example implementation with Typescript/Python of the webhook:

import { users } from './users'; // Mock user solution

interface AllocateGameUserRequest {
  scope_user_id: string;
  new_pley_game_user_id: string;
  unlinked_pley_game_user_id?: string | null;
}

export function handleAllocateGameUser(req: AllocateGameUserRequest): string {
  const { scope_user_id, new_pley_game_user_id, unlinked_pley_game_user_id } = req;

  // Get existing user.
  const existingUser = users.getByScopeUserId(scope_user_id);

  if (existingUser) {
    if (existingUser.pley_game_user_id) {
      // 1. Existing web user
      return existingUser.pley_game_user_id;
    }

    // 2. Existing non-web user
    users.setPleyGameUserId(existingUser.id, new_pley_game_user_id);
    return new_pley_game_user_id;
  }

  if (unlinked_pley_game_user_id) {
    let guestUser = users.getByPleyGameUserId(unlinked_pley_game_user_id);

    if (!guestUser) {
      guestUser = users.createNewGameUser();
      users.setPleyGameUserId(guestUser.id, unlinked_pley_game_user_id);
    }

    users.setScopeUserId(guestUser.id, scope_user_id);
    // 3. Adopt guest progress
    return unlinked_pley_game_user_id;
  }

  // 4. Brand new user
  const newUser = users.createNewGameUser();
  users.setPleyGameUserId(newUser.id, new_pley_game_user_id);
  users.setScopeUserId(newUser.id, scope_user_id);

  return new_pley_game_user_id;
}
# This function takes the response as a JSON object and returns the Pley Game User ID
def handle_allocate_game_user(req):
    existing_game_user = users.get_by_scope_user_id(req.scope_user_id)

    if existing_game_user is not None:
        if existing_game_user.pley_game_user_id is not None:
            # 1. Existing web progress
            return existing_game_user.pley_game_user_id

        users.set_pley_game_user_id(existing_game_user.id, req.new_pley_game_user_id)
        # 2. Existing non-web progress
        return req.new_pley_game_user_id

    if req.unlinked_pley_game_user_id is not None:
        game_user = users.get_by_pley_game_user_id(req.unlinked_pley_game_user_id)
        if game_user is None:
          game_user = users.create_new_game_user()
          users.set_pley_game_user_id(game_user.id, req.unlinked_pley_game_user_id)
        users.set_scope_user_id(game_user.id, req.scope_user_id)
        # 3. Adopt guest progress
        return req.unlinked_pley_game_user_id

    game_user = users.create_new_game_user()
    users.set_pley_game_user_id(game_user.id, req.new_pley_game_user_id)
    users.set_scope_user_id(game_user.id, req.scope_user_id)

    # 4. New player
    return req.new_pley_game_user_id
📘

Webhook Info

Pley uses the 'Standard Webhook"-specification format . Read more here!

Webhook calls to Pley are cached for 24 hours, meaning Pley does not call the endpoint with the same parameter within 24 hours (including invalid responses). This means that if your server returns a bad response for a given user, it will take up to 24 hours before this user can successfully authenticate again.

Article: Webhook HTTP API Rereferences