Authenticate Using Google Play Games Services with C++

You can use Google Play Games services to sign in players to an Android game built on Firebase and written in C++. To use Google Play Games services sign-in with Firebase, first sign in the player with Google Play Games, and request an OAuth 2.0 auth code when you do so. Then, pass the auth code to PlayGamesAuthProvider to generate a Firebase credential, which you can use to authenticate with Firebase.

Before you begin

Add Firebase to your Android NDK project

Add Firebase to your Android NDK project by following the Android setup steps of the Firebase C++ SDK setup guide.

Include the Firebase C++ SDK in your project's native code make file:

CMake

In your top-level CMakeLists.txt file:

set(FIREBASE_CPP_SDK_DIR "/path/to/firebase_cpp_sdk")
string(REGEX REPLACE "(.*)_.*" "\\1" STL ${ANDROID_STL})

add_library(firebase_app STATIC IMPORTED)
set_target_properties(firebase_app PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libapp.a)

add_library(firebase_auth STATIC IMPORTED)
set_target_properties(firebase_auth PROPERTIES IMPORTED_LOCATION
    ${FIREBASE_CPP_SDK_DIR}/libs/android/${ANDROID_ABI}/${STL}/libauth.a)

...

target_link_libraries(
    ...
    firebase_app
    firebase_auth)

ndk-build

In your Android.mk file:

STL := $(firstword $(subst _, ,$(APP_STL)))
FIREBASE_CPP_SDK_DIR := /path/to/frebase_cpp_sdk
FIREBASE_LIBRARY_PATH := \
    $(FIREBASE_CPP_SDK_DIR)/libs/android/$(TARGET_ARCH_ABI)/$(STL)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_app
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libapp.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_auth
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libauth.a
LOCAL_EXPORT_C_INCLUDES := $(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

In your module-level build.gradle file, declare Firebase as a dependency:

dependencies {
    implementation 'com.google.firebase:firebase-auth:16.0.3'
    implementation 'com.google.android.gms:play-services-base:15.0.1'
    implementation 'com.google.android.gms:play-services-auth:15.0.1'
}

Set up your Firebase project

  1. Set your game's SHA-1 fingerprint from the Settings page of the Firebase console.

    You can get the SHA-1 fingerprint of your key with the keytool command:

    keytool -exportcert -list -v \
        -alias YOUR-KEY-NAME -keystore PATH-TO-KEYSTORE

  2. Enable Google Play Games as a sign-in provider:

    1. Find your project's web server client ID and client secret. The web server client ID identifies your Firebase project to the Google Play auth servers.

      To find these values:

      1. Open your Firebase project in the Google APIs console credentials page.
      2. In the OAuth 2.0 client IDs section, open the Web client (auto created by Google Service) details page. This page lists your web server client ID and secret.
    2. Then, in the Firebase console, open the Authentication section.

    3. On the Sign in method tab, enable the Play Games sign-in provider. You will need to specify your project's web server client ID and client secret, which you got from the APIs console.

  1. Open the Google Play console and click Games services.
  2. Click Add new game. In the new game dialog, click I already use Google APIs in my game and click the name of your Firebase project in the list. Select a game category, then click Continue to go to the Game Details page.
  3. At the end of the Game Details page, ensure that all required APIs are enabled.
  4. Then, open the Linked apps page and click Android. Specify your game's package name, and click Save and continue. The console will display your Android client ID. You can ignore this value.
  5. On the Testing page, whitelist the email addresses of any users who need to be able to sign in to your game before you release it on the Play store.

Integrate Play Games sign-in into your game

Before you can sign players in to your game, you must integrate Google Play Games sign-in.

The easiest and recommended way to add support for Play Games sign-in to a C++ Android project is to use the Google Sign-in C++ SDK.

To add Play Games sign-in to your game using the Google Sign-in C++ SDK, do the following:

  1. Clone or download the Google Sign-in Unity plugin repository, which also contains the C++ SDK.

  2. Build the project contained in the staging/native/ directory, either using Android Studio or gradlew build.

    The build copies its output to a directory named google-signin-cpp.

  3. Include the Google Sign-in C++ SDK in your game's native code make file:

    CMake

    In your top-level CMakeLists.txt file:

    set(GSI_PACKAGE_DIR "/path/to/google-signin-cpp")
    add_library(lib-google-signin-cpp STATIC IMPORTED) set_target_properties(lib-google-signin-cpp PROPERTIES IMPORTED_LOCATION     ${GSI_PACKAGE_DIR}/lib/${ANDROID_ABI}/libgoogle-signin-cpp.a )
    ...
    target_link_libraries(     ...     lib-google-signin-cpp)

    ndk-build

    In your Android.mk file:

    include $(CLEAR_VARS)
    LOCAL_MODULE := google-signin-cpp
    GSI_SDK_DIR := /path/to/google-signin-cpp
    LOCAL_SRC_FILES := $(GSI_SDK_DIR)/lib/$(TARGET_ARCH_ABI)/libgoogle-signin-cpp.a
    LOCAL_EXPORT_C_INCLUDES := $(GSI_SDK_DIR)/include
    include $(PREBUILT_STATIC_LIBRARY)
    

  4. Next, include the Java helper component, which is required by the C++ SDK.

    To do so, in your project-level build.gradle file, add the SDK build output directory as a local repository:

    allprojects {
        repositories {
            // ...
            flatDir {
                dirs 'path/to/google-signin-cpp'
            }
        }
    }
    

    And, in your module-level build.gradle file, declare the helper component as a dependency:

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:15.0.1'
        // Depend on the AAR built with the Google Sign-in SDK in order to add
        // the Java helper classes, which are used by the C++ library.
        compile(name:'google-signin-cpp-release', ext:'aar')
    }
    
  5. Then, in your game, configure a GoogleSignIn object to use Play Games sign-in and to retrieve a server auth code:

    #include "google_signin.h"
    #include "future.h"
    
    using namespace google::signin;
    
    // ...
    
    GoogleSignIn::Configuration config = {};
    config.web_client_id = "YOUR_WEB_CLIENT_ID_HERE";
    config.request_id_token = false;
    config.use_game_signin = true;
    config.request_auth_code = true;
    
    GoogleSignIn gsi = GoogleSignIn(GetActivity(), GetJavaVM());
    gsi.Configure(config);
    
  6. Finally, call SignIn() to sign the player in to Play Games:

    Future<GoogleSignIn::SignInResult> &future = gsi.SignIn();
    

    When the Future returned by SignIn() resolves, you can get the server auth code from the result:

    if (!future.Pending()) {
        const GoogleSignIn::StatusCode status =
                static_cast<GoogleSignIn::StatusCode>(future.Status());
        if (status == GoogleSignIn::kStatusCodeSuccess) {
            // Player successfully signed in to Google Play! Get auth code to
            //   pass to Firebase
            const GoogleSignIn::SignInResult result =
                    static_cast<GoogleSignIn::SignInResult>(future.Result());
            const char* server_auth_code = result.User.GetServerAuthCode();
        }
    }
    

Authenticate with Firebase

After the player signs in with Play Games, you can use the auth code to authenticate with Firebase.

  1. After the player has successfully signed in using Play Games, get an auth code for the player's account.

  2. Then, exchange the auth code from Play Games services for a Firebase credential, and use the Firebase credential to authenticate the player:

    firebase::auth::Credential credential =
        firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code);
    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredential(credential);
    
  3. If your program has an update loop that runs regularly (say at 30 or 60 times per second), you can check the results once per update with Auth::SignInWithCredentialLastResult:

    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredentialLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        firebase::auth::User* user = *result.result();
        printf("Sign in succeeded for `%s`\n", user->display_name().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }

    Or, if your program is event driven, you may prefer to register a callback on the Future.

Register a callback on a Future

Some programs have Update functions that are called 30 or 60 times per second. For example, many games follow this model. These programs can call the LastResult functions to poll asynchronous calls. However, if your program is event driven, you may prefer to register callback functions. A callback function is called upon completion of the Future.
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::User*> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
The callback function can also be a lambda, if you prefer.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::User*> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

Next steps

After a user signs in for the first time, a new user account is created and linked to their Play Games ID. This new account is stored as part of your Firebase project, and can be used to identify a user across every app in your project.

In your game, you can get the user's Firebase UID from the firebase::auth::User object:

firebase::auth::User* user = auth->current_user();
if (user != nullptr) {
  std::string playerName = user->displayName();

  // The user's ID, unique to the Firebase project.
  // Do NOT use this value to authenticate with your backend server,
  // if you have one. Use firebase::auth::User::Token() instead.
  std::string uid = user->uid();
}

In your Firebase Realtime Database and Cloud Storage Security Rules, you can get the signed-in user's unique user ID from the auth variable, and use it to control what data a user can access.

To get a user's Play Games player information or to access Play Games services, use the APIs provided by the Google Play Games services C++ SDK.

To sign out a user, call SignOut():

auth->SignOut();

Send feedback about...

Need help? Visit our support page.