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.
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:- Set the server client ID to the ID you created in the Google APIs console. Note this is your server's client ID, not your Android client ID.
- Configure the client to show all Google Accounts on the device—that is, don't filter by authorized accounts.
- Optionally, you can also request the verified phone number for the account.
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.