Authentication on wearables

Wear OS apps can run standalone, without a companion app. This means that a Wear OS app needs to manage authentication on its own when accessing data from the internet. But the watch's small screen size and reduced input capabilities limit the authentication options that a Wear OS app can use.

This guide covers the recommended authentication methods for Wear OS apps as well as alternatives when those methods don't fit an app's use case.

To learn more about how to design a good sign-in experience, view the Sign-in UX guide.

Guest mode

Don't require authentication for all functionality. Instead, provide as many features as possible to the user without requiring them to sign in.

Users might discover and install your Wear app without having used the mobile app, so they might not have an account and might not know what features it offers. Make sure the guest mode functionality accurately showcases your app's features.

Recommended authentication methods

Use the following authentication methods to enable standalone Wear OS apps to obtain user authentication credentials.

Pass tokens using the data layer

The phone companion app can securely transfer authentication data to the Wear OS app using the Wearable Data Layer. Transfer credentials as messages or data items.

This type of authentication typically doesn't require any action from the user. However, avoid performing authentication without informing the user that they are being signed in. You can inform the user using a simple, dismissible screen that shows them their account is being transferred from mobile.

Important: Your Wear app must offer at least one other authentication method, because this option works only on Android-paired watches when the corresponding mobile app is installed. Provide an alternate authentication method for users who don't have the corresponding mobile app or whose Wear OS device is paired with an iOS device.

Pass tokens using the data layer from the mobile app, as shown in the following example:

val token = "..." // Auth token to transmit to the wearable device.
val dataClient: DataClient = Wearable.getDataClient(context)
val putDataReq: PutDataRequest = PutDataMapRequest.create("/auth").run {
    dataMap.putString("token", token)
    asPutDataRequest()
}
val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)

Listen for data change events on the watch app as shown in the following example:

val dataClient: DataClient = Wearable.getDataClient(context)
dataClient.addListener{ dataEvents ->
    dataEvents.forEach { event ->
        if (event.type == DataEvent.TYPE_CHANGED) {
            val dataItemPath = event.dataItem.uri.path ?: ""
            if (dataItemPath.startsWith("/auth")) {
                val token = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("token")
                // Display interstitial screen to notify the user they are being signed in.
                // Then, store the token and use it in network requests.
            }
        }
    }
}

For more information on using the Wearable Data Layer, see Send and sync data on Wear OS.

Use OAuth 2.0

Wear OS supports two OAuth 2.0-based flows, which are described in the sections that follow:

  • Authorization Code Grant with Proof Key for Code Exchange (PKCE), as defined in RFC 7636
  • Device Authorization Grant, as defined in RFC 8628

Note: To help ensure that your app doesn’t shut down when the watch goes into ambient mode, enable Always-on using AmbientModeSupport.attach in the activity performing authentication. For more information about best practices in Ambient Mode, see Keep your app visible on Wear.

Proof Key for Code Exchange (PKCE)

To effectively use PKCE, use RemoteAuthClient.

To perform an auth request from your Wear OS app to an OAuth provider, create an OAuthRequest object. This object consists of a URL to your OAuth endpoint for getting a token and a CodeChallenge object. The following code shows an example of creating an auth request:

val request = OAuthRequest.Builder(this.applicationContext)
    .setAuthProviderUrl(Uri.parse("https://...."))
    .setClientId(clientId)
    .setCodeChallenge(codeChallenge)
    .build()

After you build the auth request, send it to the companion app using the sendAuthorizationRequest() method:

val client = RemoteAuthClient.create(this)
client.sendAuthorizationRequest(request,
    { command -> command?.run() },
    object : RemoteAuthClient.Callback() {
        override fun onAuthorizationResponse(
            request: OAuthRequest,
            response: OAuthResponse
        ) {
            // Extract the token from the response, store it and use it in network requests.
        }

        override fun onAuthorizationError(errorCode: Int) {
            // Handle error
        }
    }
)

This request triggers a call to the companion app, which then presents an authorization UI in a web browser on the user's mobile phone. The OAuth 2.0 provider authenticates the user and obtains the user's consent for the requested permissions. The response is sent to the automatically generated redirect URL.

After a successful or failed authorization, the OAuth 2.0 server redirects to the URL specified in the request. If the user approves the access request, then the response contains an authorization code. If the user doesn't approve the request, the response contains an error message.

The response is in the form of a query string and looks like one of the following examples:

  https://wear.googleapis.com/3p_auth/com.your.package.name?code=xyz
  https://wear.googleapis-cn.com/3p_auth/com.your.package.name?code=xyz

This loads a page that directs the user to the companion app. The companion app verifies the response URL and relays the response to the third-party watch app using the onAuthorizationResponse API.

The watch app can then exchange the authorization code for an access token.

Note: Once the OAuthRequest is built, you can find your redirect URL by accessing redirectUrl.

Device Authorization Grant

When using Device Authorization Grant, the user opens the verification URI on another device. Then the authorization server asks them to approve or deny the request.

To make this process easier, use a RemoteActivityHelper to open a web page on the user's paired mobile device, as shown in the following example:

// Request access from the authorization server and receive Device Authorization Response.
val verificationUri = "..." // Extracted from the Device Authorization Response.
RemoteActivityHelper.startRemoteActivity(
    this,
    Intent(Intent.ACTION_VIEW)
        .addCategory(Intent.CATEGORY_BROWSABLE)
        .setData(Uri.parse(verificationUri)),
    null
)
// Poll the authorization server to find out if the user completed the user authorization
// step on their mobile device.

If you have an iOS app, use universal links to intercept this intent in your app instead of relying on the browser to authorize the token.

Other authentication methods

Wear OS supports additional sign-in methods, described in the following sections.

Google Sign-In

Google Sign-In lets the user sign in with their existing Google account. It offers the best user experience and is easy to support, especially if you already implement it in your handheld apps.

After the recommended authentication methods described previously, Google Sign-In is the next preferred solution because it also works well on iOS. The following section describes how to complete a basic Google Sign-In integration.

Prerequisites

Before you can start integrating Google Sign-In in your Wear OS app, you must configure a Google API Console project and set up your Android Studio project. For more information, see Start Integrating Google Sign-In into Your Android App.

If you use Google Sign-In with an app or site that communicates with a backend server, there are two additional prerequisites:
  • Create an OAuth 2.0 web application client ID for your backend server. This client ID is different from your app's client ID. For more information, see Enabling Server-Side Access.
  • Identify the currently signed-in user securely on the server by sending the user's ID token using HTTPS. To learn how to authenticate your user on the backend server, see Authenticate with a backend server.

Integrate Google Sign-In into your app

Review and implement the following steps, which are detailed in the sections that follow, to integrate Google Sign-In into your Wear OS app:

  1. Configure Google Sign-In.
  2. Add a Google Sign-In button.
  3. Start the sign-in flow when the sign-in button is tapped.

Configure Google Sign-In and build the GoogleApiClient object

In your sign-in activity's onCreate() method, configure Google Sign-In to request the user data required by your app. Then, create a GoogleApiClient object with access to the Google Sign-In API and the options you specified. These steps are shown in the following example:

  public class MyNewActivity extends AppCompatActivity {

    private static final int RC_SIGN_IN = 9001;

    private GoogleSignInClient mSignInClient;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        GoogleSignInOptions options =
               new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                        .build();

        mSignInClient = GoogleSignIn.getClient(this, options);
    }
  }

Add a Google Sign-In button to your app

Complete the following steps to add a Google Sign-In button:
  1. Add the SignInButton to your app's layout:
  2.  <com.google.android.gms.common.SignInButton
     android:id="@+id/sign_in_button"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content" />
    
  3. In your app's onCreate() method, register your button's OnClickListener to sign the user in when tapped:
  4. Kotlin

    findViewById<View>(R.id.sign_in_button).setOnClickListener(this)
    

    Java

    findViewById(R.id.sign_in_button).setOnClickListener(this);
    

Create a sign-in intent and start the sign-in flow

Handle sign-in button taps in your onCLick() method by creating a sign-in intent with the getSignInIntent() method. Then start the intent with the startActivityForResult() method.

  Intent intent = mSignInClient.getSignInIntent();
  startActivityForResult(intent, RC_SIGN_IN);

The user is prompted to select a Google account to sign in with. If you requested scopes beyond profile, email, and open ID, the user is also prompted to grant access to those resources.

Finally, in the activity's onActivityResult method, retrieve the sign-in result with getSignInResultFromIntent. After you retrieve the sign-in result, you can check whether the sign-in succeeded using the isSuccess method. If sign-in succeeds, you can call the getSignInAccount method to get a GoogleSignInAccount object that contains information about the signed-in user, such as the user's name. These steps are shown in the following example:

Kotlin

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

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...).
    if (requestCode == RC_SIGN_IN) {
        Auth.GoogleSignInApi.getSignInResultFromIntent(data)?.apply {
            if (isSuccess) {
                // Get account information.
                fullName = signInAccount?.displayName
                mGivenName = signInAccount?.givenName
                mFamilyName = signInAccount?.familyName
                mEmail = signInAccount?.email
            }
        }
    }
}

Java

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

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...).
    if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult signInResult = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        if (signInResult.isSuccess()) {
            GoogleSignInAccount acct = signInResult.getSignInAccount();

            // Get account information.
            fullName = acct.getDisplayName();
            givenName = acct.getGivenName();
            familyName = acct.getFamilyName();
            email = acct.getEmail();
        }
    }
}

To see a sample app that implements Google Sign-In, see the Android Wear Google Sign-In Sample on GitHub.

Custom code authentication

As an alternative to the authentication methods described previously, you can require the user to authenticate from another device, such as a mobile phone or tablet, and obtain a short-lived numeric code. The user then enters the code on their Wear OS device to confirm their identity and receives an auth token.

This authenticatation flow either uses your app’s login module, or manually integrates a third-party auth provider sign-in method into your app’s code. Although this authentication method requires manual work and additional effort to make it more secure, you can use this method if you need authentication earlier in your standalone Wear OS apps.

The auth flow for this setup works as follows:

  1. The user performs an action with the Wear OS app requiring authorization.
  2. The Wear OS app presents an authentication screen to the user and instructs the user to enter a code from a specified URL.
  3. The user switches to a mobile device, tablet, or PC, and then launches a browser, navigates to the URL specified on the Wear OS app, and logs in.
  4. The user receives a short-lived numeric code that they enter into the Wear OS app authentication screen using the onboard keyboard in Wear OS:

  5. From this point, you can use the entered code as proof that this is the correct user and exchange the code for an auth token stored and secured on the Wear OS device for authenticated calls going forward.

Note: The code that the user generates must be purely numerical and can't contain any alphabetic characters.

This auth flow is depicted in the following chart: