We recommend that you authenticate players and securely pass the player's identity to the backend server. This 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, once the player signs in successfully, you can request a special single-use code (called the server auth code) from the Play Games Services v2 SDK, which 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 for Android Games.
The following steps are required for offline access:
- In the Google Play Console: Create a credential for your game server. The OAuth client type of the credential will be "web".
- 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.
- 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
You'll first need to add your game in the Google Play Console, as described in Set Up Google Play Games Services, and integrate Play Games Services Sign In with your game.
Create a server-side web app
Google Play Game services does not provide backend support for Web games. However, it does provide backend 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:
- In the Google Play Console, select a game.
- Go to Play Games Services > Setup and management > Configuration.
- Select Add credential to be brought to the Add credential page.
Select Game server as the credential type and continue onto the
Authorization section.
- If your game server already has an OAuth client ID select it from the drop down menu. After saving your changes, move onto the next section.
- If you don't have an existing OAuth client ID for your game server, you can
create one.
- Click Create OAuth client and follow the Create OAuth Client ID link.
- This will bring you to the Google Cloud Platform's Create OAuth Client ID page for your project associated with your game.
- Fill out the page's form and click create. Be sure to set the Application type to Web application.
- Return to the Add credential page's Authorization section, select the newly created OAuth client and save your changes.
Get the server auth code
To retrieve a server auth code that your game can use for access tokens on your backend server:
Call
requestServerSideAccess
from the client.- Be sure that you use the OAuth Client ID registered for your game server and not the OAuth Client ID of your Android application.
- (Optional) If your game server requires offline access (long lived access using a refresh token) to Play Games Services, you can set the forceRefreshToken parameter to true.
GamesSignInClient gamesSignInClient = PlayGames.getGamesSignInClient(this); gamesSignInClient .requestServerSideAccess(OAUTH_2_WEB_CLIENT_ID, /* forceRefreshToken= */ false) .addOnCompleteListener( task -> { if (task.isSuccessful()) { String serverAuthToken = task.getResult(); // Send authentication code to the backend game server to be // exchanged for an access token and used to verify the player // via the Play Games Services REST APIs. } else { // Failed to retrieve authentication code. } });
Send the OAuth auth code token to your backend server so it may be exchanged, the Player ID verified against the Play Games Services REST APIs, and then authenticated with your game.
Send the server auth code
Send the server auth code to your backend server to exchange for access and refresh tokens. Use the access token to call the 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 uses 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 shouldn't 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;
}
Call REST APIs from the server
See 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
See the Friends guide for details.
To retrieve the player's list of friends, call Players.list with
friends_all
as thecollection
.To verify whether you have access to a friends list, call Players.get with
me
as theplayerID
, and view theprofileSettings.friendsListVisibility
field in the response.
Achievements
See the Achievements guide for details.
To get a list of current achievements, call AchievementDefinitions.list.
Combine that with a call to Achievements.list to find out which ones the player unlocked.
Call Achievements.unlock to unlock a player achievement.
Call Achievements.increment to report progress on an achievement, and find out if the player unlocked it.
If you are debugging a game that hasn't reached production, you can call Achievements.reset or Achievements.resetAll from the Management APIs to reset achievements to their original state.
Leaderboards
See the Leaderboards guide for details.
Want to get a list of all scoreboards in the game? Make a call to Leaderboards.list.
If a player is done with a game, you can submit their score to Scores.submit and find out if it is a new high score.
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.
If you debugging a game, you can call Scores.reset from the Management APIs to reset all scores for that player from a particular leaderboard.