Authentication on wearables

The watch's small screen size and reduced input capabilities limit authentication options that a Wear OS app can use. In addition, 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.

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 may discover and install your Wear app without having used the mobile app in the past, and thus may not have an account. In this case, the guest mode functionality should accurately showcase your app's features to incentivize users to create an account.

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, as 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 the following OAuth 2.0 based flows:

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

Note: To 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 on 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. See the following example of creating an auth request:

val request = OAuthRequest.Builder(applicationContext.packageName)
    .setAuthProviderUrl(Uri.parse("https://...."))
    .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, 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, which then presents an authorization UI to the user's mobile in a web browser. The OAuth 2.0 provider authenticates the user and obtains the user's consent for the requested permissions. The response is sent to your backend server using the redirect URL you specified.

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 of a query string form, as shown in the following example:

https://example.com/oauthtokens?code=xyz

After the backend server receives the authorization code, it can exchange the authorization code for an access token. Then the backend server loads a page that leads the user to the Wear OS mobile app that's registered as a receiver for URLs of the following form:

  https://wear.googleapis.com/3p_auth/com.your.package.name?accessToken=abc&refreshToken=xyz

The mobile app verifies the response URL and relays the response to the third-party watch app using the onAuthorizationResponse API.

Note: Make sure that the app package name is the third path component in the redirect URL. The redirect_uri must be equal to https://wear.googleapis.com/3p_auth/<receiving app packagename>. For example, https://wear.googleapis.com/3p_auth/com.package.name.

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 RemoteIntent 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
RemoteIntent.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

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.

Password-based authentication

If your server doesn't support one of the OAuth 2.0 flows described, display a username and password prompt to the user.

Make sure to include hints for autofill to ensure the user is offered a saved password if they have one available. The following example sets a password hint on EditText in your layout file:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:autofillHints="password" />

See Optimize your app for autofill for more information.

Other authentication methods

Wear OS supports additional sign in methods.

Google Sign-In

Google Sign-In enables the user to sign in with their existing Google account. It offers the best user experience and is easy to support, especially if you are already implementing these solutions in your handheld apps.

Google Sign-In is the most preferred solution as 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 the Start Integrating guide for Google Sign-In.

Note: If you use Google Sign-In with an app or site that communicates with a backend server, then 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.

Important: If your app communicates with a backend server, 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.

Integrating Google Sign-In into your app

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 clicked.

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 Google Sign-In API and the options you specified.

Kotlin

// Configure sign-in to request the user's ID, email address, and basic
// profile. The ID and basic profile are included in DEFAULT_SIGN_IN.
// If you need to request additional scopes to access Google APIs, specify them with
// requestScopes().
googleApiClient = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestEmail()
        .build()
        .let { signInConfigBuilder ->
            // Build a GoogleApiClient with access to the Google Sign-In API and the
            // options specified in the sign-in configuration.
            GoogleApiClient.Builder(this)
                    .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                    .addApi(Auth.GOOGLE_SIGN_IN_API, signInConfigBuilder)
                    .build()
        }

Java

// Configure sign-in to request the user's ID, email address, and basic
// profile. The ID and basic profile are included in DEFAULT_SIGN_IN.
// If you need to request additional scopes to access Google APIs, specify them with
// requestScopes().
GoogleSignInOptions.Builder signInConfigBuilder = new GoogleSignInOptions
        .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestEmail()
        .build();

// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified in the sign-in configuration.
googleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
        .addApi(Auth.GOOGLE_SIGN_IN_API, signInConfigBuilder)
        .build();

Add a Google Sign-In button to your app

  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 in the user when clicked.
  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

When the sign-in button is clicked, handle sign-in button taps in your onCLick() method by creating a sign-in intent with the getSignInIntent method, and then starting the intent with the startActivityForResult method.

Kotlin

Auth.GoogleSignInApi.getSignInIntent(googleApiClient).also { signInIntent ->
    startActivityForResult(signInIntent, RC_SIGN_IN)
}

Java

Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);

The user is prompted to select a Google account to sign in with. If you requested scopes beyond profile, email, and openid, 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 if the sign-in succeeded using the isSuccess method. If sign-in succeedes, 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.

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
public 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 sample app on GitHub.

Custom code authentication

This authentication method requires the user to authenticate from an external source (mobile device/ tablet / pc) and obtain a short-lived code that they enter to prove their identity and exchange it for an auth token on their Wear OS device. In this method, you can authenticate users to your Wear OS app by either using your app’s login module or by manually integrating any 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, if you need authentication earlier on in your standalone Wear OS apps, you can use this method.

The auth flow for this setup works as follows:

  1. The user performs an action with the third-party app requiring authorization.
  2. The third-party 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, launches a browser, navigates to the URL specified on the Wear OS app, and logs in.
  4. The user receives a short-lived code that they enter into the Wear OS app authentication screen using the onboard keyboard in Wear OS to get authenticated:

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