Enabling Server-Side Access to Google Play Games Services

If your game uses a backend server, we recommend that you use Google Sign-In to authenticate players and securely pass the player's identity to the backend server. This also enables your game to securely retrieve the player's identity and other data without being exposed to potential tampering while passing through the device.

In this scenario, your game prompts the player to sign in to Google Play games services as usual. When the player signs in successfully, the GoogleSignInAccount object contains a special single-use code (called the server auth code) that the client passes to the server. Then, on the server, exchange the server auth code for an OAuth 2.0 token that the server can use to make calls to the Google Play Games Services API.

For additional guidance on adding sign-in in your games, see Sign-in in Android Games.

To see a detailed code sample showing how to use Google Sign-In to authenticate players, see the clientserverskeleton sample on GitHub.

The following steps are required for offline access:

  1. In the Google Play Console: Create a credential for your game server. The OAuth client type of the credential will be "web".
  2. In the Android app: As part of sign-in, request a server auth code for your server's credential, and pass that to your server.
  3. On your game server: Exchange the server auth code for an OAuth access token using Google auth services, and then use this to call the Play Games Services REST APIs.

Before you begin

Before you can integrate Google Sign-In into your game, you'll first need to add your game in the Google Play Console, as described in Setting Up Google Play Games Services.

Create an associated server-side web application for your game

Google Play Game services does not provide back-end support for Web games. However, it does provide back-end server support for your Android game's server.

If you want to use the REST APIs for Google Play Games services in your server-side app, follow these steps:

  1. Create an associated web app for your game in the Linked Apps section of the Google Play Console. Note that the launch_url is not used for this flow and can be left blank.
  2. To get the credential information for your app, follow these steps:
    1. From your game in the Google Play Console, click Game Details.
    2. Scroll down to the API Console Project section and click on the link to the API console project.
    3. From the APIs & Services > Credentials screen in the Google API Console, download the client_secret.json file for your web app and save it to a location that your server can access. Record the client ID of the credential for later reference.
  3. Restart your server-side app so it’s ready to accept requests from your game’s client app.

Performing sign-in on the client

The GoogleSignInClient class is the main entry point to retrieve the account of the currently signed-in player, and to sign-in the player if they have not previously done so on your app in the device.

To create a sign-in client, follow these steps:

  1. Create a sign-in client via the GoogleSignInOptions object. In the GoogleSignInOptions.Builder to configure your sign-in, you must specify GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN.
  2. You must also specify that your game requires an auth code for your backend server by calling the GoogleSignInOptions.Builder.requestServerAuthCode() method with server's client ID as the parameter. You will retrieve the auth code later for access tokens on your backend server, as described in Get the server auth code.
  3. Call the GoogleSignIn.getClient() method and pass in options you previously configured. If the call is successful, Google Sign-In API returns an instance of GoogleSignInClient.
  4. Once you have obtained the GoogleSignInClient instance, you should proceed to sign the player in silently from the activity’s onResume(), as described in Performing silent sign-in.

Here's an example:

private static final int RC_SIGN_IN = 9001;
private GoogleSignInClient mGoogleSignInClient;

private void startSignInForAuthCode() {

  // Client ID for your backend server.
  String webClientId = getString(R.string.webclient_id);

  GoogleSignInOptions signInOption = new
      GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
      .requestServerAuthCode(webClientId)
      .build();

  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  Intent intent = signInClient.getSignInIntent();
  startActivityForResult(intent, RC_SIGN_IN);
}

Get the server auth code

To retrieve a server auth code that your game can use for access tokens on your backend server, call the getServerAuthCode() method on the GoogleSignInAccount object that Google Sign-In returns on successful player sign-in.

Here's an example:

// Auth code to send to backend server.
private String mServerAuthCode;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RC_SIGN_IN) {
    GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
    if (result.isSuccess()) {
      mServerAuthCode = result.getSignInAccount().getServerAuthCode();
    } else {
      String message = result.getStatus().getStatusMessage();
      if (message == null || message.isEmpty()) {
        message = getString(R.string.signin_other_error);
      }
      new AlertDialog.Builder(this).setMessage(message)
          .setNeutralButton(android.R.string.ok, null).show();
    }
  }
}

Exchange the server auth code for an access token on the server

Send the server auth code to your backend server to exchange for access and refresh tokens. Use the access token to call the Google Play Games Services API on behalf of the player and, optionally, store the refresh token to acquire a new access token when the access token expires.

The following code snippet shows how you might implement the server-side code in the Java programming language to exchange the server auth code for access tokens. It is using the clientserverskeleton sample app:

/**
 * Exchanges the authcode for an access token credential.  The credential
 * is the associated with the given player.
 *
 * @param authCode - the non-null authcode passed from the client.
 * @param player   - the player object which the given authcode is
 *                 associated with.
 * @return the HTTP response code indicating the outcome of the exchange.
 */
private int exchangeAuthCode(String authCode, Player player) {
try {

    // The client_secret.json file is downloaded from the Google API
    // console.  This is used to identify your web application.  The
    // contents of this file should not be shared.
    //
    File secretFile = new File("client_secret.json");

    // If we don't have the file, we can't access any APIs, so return
    // an error.
    if (!secretFile.exists()) {
        log("Secret file : " + secretFile
                .getAbsolutePath() + "  does not exist!");
        return HttpServletResponse.SC_FORBIDDEN;
    }

    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
            JacksonFactory.getDefaultInstance(), new
            FileReader(secretFile));

    // Extract the application id of the game from the client id.
    String applicationId = extractApplicationId(clientSecrets
            .getDetails().getClientId());

    GoogleTokenResponse tokenResponse =
            new GoogleAuthorizationCodeTokenRequest(
            HTTPTransport,
            JacksonFactory.getDefaultInstance(),
            "https://oauth2.googleapis.com/token",
            clientSecrets.getDetails().getClientId(),
            clientSecrets.getDetails().getClientSecret(),
            authCode,
            "")
            .execute();

    log("hasRefresh == " + (tokenResponse.getRefreshToken() != null));
    log("Exchanging authCode: " + authCode + " for token");
    Credential credential = new Credential
            .Builder(BearerToken.authorizationHeaderAccessMethod())
            .setJsonFactory(JacksonFactory.getDefaultInstance())
            .setTransport(HTTPTransport)
            .setTokenServerEncodedUrl("https://www.googleapis.com/oauth2/v4/token")
            .setClientAuthentication(new HttpExecuteInterceptor() {
                @Override
                public void intercept(HttpRequest request)
                        throws IOException {
                        }
            })
            .build()
            .setFromTokenResponse(tokenResponse);

    player.setCredential(credential);

    // Now that we have a credential, we can access the Games API.
    PlayGamesAPI api = new PlayGamesAPI(player, applicationId,
            HTTPTransport, JacksonFactory.getDefaultInstance());

    // Call the verify method, which checks that the access token has
    // access to the Games API, and that the player id used by the
    // client matches the playerId associated with the accessToken.
    boolean ok = api.verifyPlayer();

    // Call a Games API on the server.
    if (ok) {
        ok = api.updatePlayerInfo();
        if (ok) {
            // persist the player.
            savePlayer(api.getPlayer());
        }
    }

    return ok ? HttpServletResponse.SC_OK :
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

  } catch (IOException e) {
    e.printStackTrace();
  }
  return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}

To learn more about accessing Google APIs from a backend server on behalf of a signed-in player, see Enabling Server-Side Access.

Handle player sign-out

To sign players out of your game, call the signOut() method on the GoogleSignInClient. For an example code snippet, see Signing the player out.

Call REST APIs from the server

Refer to REST APIs for Google Play Games services for a full description of API calls available.

Examples of REST API calls that you may find useful include the following:

Player

  • Want to get the signed-in player's ID and profile data? Call Players.get with 'me' as the ID.

Friends

Make sure you review the Friends guide, which explains Friends in more detail.

Achievements

Make sure you review the Achievements guide, which explains achievements in more detail.

Leaderboards

Make sure you review the Leaderboards guide, which explains leaderboards in more detail.

  • Want to get a list of all scoreboards in the game? Make a call to Leaderboards.list.
  • Is the player done with a game? You can submit their score to Scores.submit and find out if this is a new high score.
  • Want to display a leaderboard? Get the data from Scores.list and show it to the user.
  • Use Scores.listWindow to find an assortment of scores close to the user's high score.
  • To get more information about the player's score in a particular leaderboard (for example, if the player is in the top 12% of all players), call Scores.get.
  • Are you debugging a game? Try calling Scores.reset from the Management APIs to reset all scores for that player from a particular leaderboard