Create new accounts with one tap

If you support signing in with Google Accounts, you can use the One Tap sign-in client to also give your users a frictionless account creation experience that never takes them out of the context of your app.

One-tap sign-up UI

When you display the One Tap UI, users are prompted to create a new account with your app using one of the Google Accounts on their device. If the user chooses to continue, you get an ID token with basic profile information—their name, profile photo, and their verified email address—which you can use to create the new account.

Implementing One Tap account creation has two parts:

  • Integrating the One Tap client into your app, which is described on this page. This is mostly the same as using One Tap sign-in, but with some differences in configuration.
  • Adding to your backend the ability to create user accounts from Google ID tokens, which is discussed in Using ID tokens on the backend.

Where should I use One Tap sign-up?

The most impactful place to offer One Tap sign-up to users is in a context where signing in would enable new features. First, try to sign the user in with a saved credential. If no saved credentials are found, offer to create a new account for the user.

Before you begin

Set up your Google APIs console project and Android project as described in Get started with One Tap sign-in.

1. Configure the One Tap client

To configure the One Tap client for account creation, do the following:

  • Do not enable password credential requests. (One-tap sign-up is only possible with token-based authentication.)
  • Enable Google ID token requests using setGoogleIdTokenRequestOptions() and these settings:

Java

public class YourActivity extends AppCompatActivity {

  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signUpRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signUpRequest = BeginSignInRequest.builder()
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.your_web_client_id))
                      // Show all accounts on the device.
                      .setFilterByAuthorizedAccounts(false)
                      .build())
              .build();

      // ...
  }
}

Kotlin

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signUpRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Show all accounts on the device.
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()
        // ...
    }
    // ...
}

2. Keep track of One Tap UI cancellation

You should keep track of whether the user has already declined to use One Tap sign-up by either closing the prompt or tapping outside of it. This can be as simple as a boolean property of your Activity. (See Stop displaying the One Tap UI, below.)

3. Display the One Tap sign-up UI

If the user hasn't declined to use One Tap to create a new account, call the client object's beginSignIn() method, and attach listeners to the Task it returns. Apps typically do this step when a One Tap sign-in request doesn't find any saved credentials—that is, in the failure listener of the sign-in request.

The One Tap client will call the success listener if the user has one or more Google Accounts set up on the device. In the success listener, get the pending intent from the Task result and pass it to startIntentSenderForResult() to start the One Tap UI.

If the user doesn't have any Google Accounts on the device, the One Tap client will call the failure listener. In this case, no action is necessary: you can simply continue presenting the app's signed-out experience, and the user can sign up with your normal account creation flow.

Java

oneTapClient.beginSignIn(signUpRequest)
        .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
            @Override
            public void onSuccess(BeginSignInResult result) {
                try {
                    startIntentSenderForResult(
                            result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                            null, 0, 0, 0);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                }
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // No Google Accounts found. Just continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

Kotlin

oneTapClient.beginSignIn(signUpRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No Google Accounts found. Just continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. Handle the user's response

The user's response to the One Tap sign-up prompt will be reported to your app using your Activity's onActivityResult() method. If the user chose to create an account, the result will be a Google ID token. If the user declined to sign up, either by closing the One Tap UI or tapping outside it, the result will return with the code RESULT_CANCELED. Your app needs to handle both possibilities.

Create an account with a Google ID token

If the user chose to sign up with a Google Account, you can get an ID token for the user by passing the intent data from onActivityResult() to the One Tap client's getSignInCredentialFromIntent() method. The credential will have a non-null googleIdToken property.

Use the ID token to create an account on your backend (see Authenticate with a backend using ID tokens) and sign the user in.

The credential also contains any additional details you have requested, such as the account's verified phone number if available.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
            }
        }
    }
    // ...
}

Stop displaying the One Tap UI

If the user declined to sign in, the call to getSignInCredentialFromIntent() will throw an ApiException with a CommonStatusCodes.CANCELED status code. When this happens, you should temporarily stop displaying the One Tap sign-in UI so you don't annoy your users with repeated prompts. The following example accomplishes this by setting a property on the Activity, which it uses to determine whether to offer the user One Tap sign-in; however, you could also save a value to SharedPreferences or use some other method.

It's important to implement your own rate limiting of One Tap sign-in prompts. If you don't, and a user cancels several prompts in a row, the One Tap client will not prompt the user for the next 24 hours.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  // ...
              } catch (ApiException e) {
                  switch (e.getStatusCode()) {
                      case CommonStatusCodes.CANCELED:
                          Log.d(TAG, "One-tap dialog was closed.");
                          // Don't re-prompt the user.
                          showOneTapUI = false;
                          break;
                      case CommonStatusCodes.NETWORK_ERROR:
                          Log.d(TAG, "One-tap encountered a network error.");
                          // Try again or just ignore.
                          break;
                      default:
                          Log.d(TAG, "Couldn't get credential from result."
                                  + e.getLocalizedMessage());
                          break;
                  }
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQ_ONE_TAP -> {
                try {
                    // ...
                } catch (e: ApiException) {
                    when (e.statusCode) {
                        CommonStatusCodes.CANCELED -> {
                            Log.d(TAG, "One-tap dialog was closed.")
                            // Don't re-prompt the user.
                            showOneTapUI = false
                        }
                        CommonStatusCodes.NETWORK_ERROR -> {
                            Log.d(TAG, "One-tap encountered a network error.")
                            // Try again or just ignore.
                        }
                        else -> {
                            Log.d(TAG, "Couldn't get credential from result." +
                                " (${e.localizedMessage})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

Next steps

When a user completes the One Tap sign-up flow, you get a Google ID token, which includes some basic profile information: the user's email address, full name, and profile picture URL. For many apps, this information is enough for you to authenticate the user on backend and create a new account.

If you require additional information to complete account creation—for instance, the user's birth date—present the user with a sign-up details flow, where you request this additional info. Then, send it to your backend to complete account creation.