Acceso a una cuenta vinculada para Android

El acceso con cuentas vinculadas habilita la opción Acceder con Google con One Tap para los usuarios que ya tienen su Cuenta de Google vinculada a tu servicio. Esto mejora la experiencia de los usuarios, ya que pueden acceder con un clic, sin tener que volver a ingresar su nombre de usuario y contraseña. También reduce las posibilidades de que los usuarios creen cuentas duplicadas en tu servicio.

El acceso a una cuenta vinculada está disponible como parte del flujo de acceso con One Tap para Android. Esto significa que no necesitas importar una biblioteca separada si tu app ya tiene habilitada la función One Tap.

En este documento, aprenderás a modificar tu app para Android a fin de que sea compatible con el Acceso con una cuenta vinculada.

Cómo funciona

  1. Puedes habilitar la opción para mostrar las cuentas vinculadas durante el flujo de acceso con One Tap.
  2. Si el usuario accedió a Google y vinculó su Cuenta de Google con su cuenta en tu servicio, se mostrará un token de ID para la cuenta vinculada.
  3. El usuario verá un mensaje de acceso con One Tap con una opción para acceder a tu servicio con su cuenta vinculada.
  4. Si el usuario decide continuar con la cuenta vinculada, el token de ID del usuario se devuelve a tu app. Debes comparar esto con el token que se envió a tu servidor en el paso 2 para identificar al usuario que accedió.

Configuración

Cómo configurar tu entorno de desarrollo

Obtén la versión más reciente de los Servicios de Google Play en tu host de desarrollo:

  1. Abre Android SDK Manager.
  1. En SDK Tools, busca Google Play Services.

  2. Si el estado de estos paquetes no es Installed, selecciónalos y haz clic en Install Packages.

Cómo configurar tu app

  1. En el archivo build.gradle de nivel de proyecto, incluye el repositorio Maven de Google en las secciones buildscript y allprojects.

    buildscript {
        repositories {
            google()
        }
    }
    
    allprojects {
        repositories {
            google()
        }
    }
    
  2. Agrega las dependencias para la API de "Vincular con Google" al archivo Gradle de nivel de la app de tu módulo, que suele ser app/build.gradle:

    dependencies {
      implementation 'com.google.android.gms:play-services-auth:21.0.0'
    }
    

Modifica tu app para Android para que admita el acceso con cuenta vinculada

Al final del flujo de acceso a una cuenta vinculada, se muestra un token de ID a tu app. Se debe verificar la integridad del token de ID antes de que el usuario acceda.

En la siguiente muestra de código, se detallan los pasos para recuperar, verificar el token de ID y, luego, hacer que el usuario acceda.

  1. Crea una actividad para recibir el resultado del intent de acceso

    Kotlin

      private val activityResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
          try {
            val signInCredentials = Identity.signInClient(this)
                                    .signInCredentialFromIntent(result.data)
            // Review the Verify the integrity of the ID token section for
            // details on how to verify the ID token
            verifyIdToken(signInCredential.googleIdToken)
          } catch (e: ApiException) {
            Log.e(TAG, "Sign-in failed with error code:", e)
          }
        } else {
          Log.e(TAG, "Sign-in failed")
        }
      }
    

    Java

      private final ActivityResultLauncher<IntentSenderResult>
        activityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartIntentSenderForResult(),
        result -> {
        If (result.getResultCode() == RESULT_OK) {
            try {
              SignInCredential signInCredential = Identity.getSignInClient(this)
                             .getSignInCredentialFromIntent(result.getData());
              verifyIdToken(signInCredential.getGoogleIdToken());
            } catch (e: ApiException ) {
              Log.e(TAG, "Sign-in failed with error:", e)
            }
        } else {
            Log.e(TAG, "Sign-in failed")
        }
    });
    
  2. Compila la solicitud de acceso

    Kotlin

    private val tokenRequestOptions =
    GoogleIdTokenRequestOptions.Builder()
      .supported(true)
      // Your server's client ID, not your Android client ID.
      .serverClientId(getString("your-server-client-id")
      .filterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                               scopes)
      .build()
    

    Java

     private final GoogleIdTokenRequestOptions tokenRequestOptions =
         GoogleIdTokenRequestOptions.Builder()
      .setSupported(true)
      .setServerClientId("your-service-client-id")
      .setFilterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                                scopes)
      .build()
    
  3. Inicia el intent de acceso pendiente

    Kotlin

     Identity.signInClient(this)
        .beginSignIn(
      BeginSignInRequest.Builder()
        .googleIdTokenRequestOptions(tokenRequestOptions)
      .build())
        .addOnSuccessListener{result ->
          activityResultLauncher.launch(result.pendingIntent.intentSender)
      }
      .addOnFailureListener {e ->
        Log.e(TAG, "Sign-in failed because:", e)
      }
    

    Java

     Identity.getSignInClient(this)
      .beginSignIn(
        BeginSignInRequest.Builder()
          .setGoogleIdTokenRequestOptions(tokenRequestOptions)
          .build())
      .addOnSuccessListener(result -> {
        activityResultLauncher.launch(
            result.getPendingIntent().getIntentSender());
    })
    .addOnFailureListener(e -> {
      Log.e(TAG, "Sign-in failed because:", e);
    });
    

Verifica la integridad del token de ID

Para verificar que el token sea válido, asegúrate de que se cumplan los siguientes criterios:

  • Google tiene la firma correcta del token de ID. Usa las claves públicas de Google (disponibles en formato JWK o PEM) para verificar la firma del token. Estas claves se rotan con regularidad. Examina el encabezado Cache-Control en la respuesta para determinar cuándo debes volver a recuperarlas.
  • El valor de aud en el token de ID es igual a uno de los IDs de cliente de tu app. Esta verificación es necesaria para evitar que los tokens de ID emitidos a una app maliciosa se usen para acceder a datos sobre el mismo usuario en el servidor de backend de tu app.
  • El valor de iss en el token de ID es igual a accounts.google.com o https://accounts.google.com.
  • No pasó la hora de vencimiento (exp) del token de ID.
  • Si necesitas validar que el token de ID represente una cuenta de organización de Google Workspace o Cloud, puedes verificar la reclamación hd, que indica el dominio alojado del usuario. Se debe usar cuando se restringe el acceso a un recurso solo a miembros de ciertos dominios. La ausencia de este reclamo indica que la cuenta no pertenece a un dominio alojado en Google.

En lugar de escribir tu propio código para realizar estos pasos de verificación, te recomendamos que uses una biblioteca cliente de la API de Google para tu plataforma o una biblioteca JWT de uso general. Para el desarrollo y la depuración, puedes llamar a nuestro extremo de validación tokeninfo.

Usa una biblioteca cliente de la API de Google

Se recomienda usar la biblioteca cliente de la API de Google para Java para validar los tokens de ID de Google en un entorno de producción.

Java

  import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
  import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
  import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

  ...

  GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
      // Specify the CLIENT_ID of the app that accesses the backend:
      .setAudience(Collections.singletonList(CLIENT_ID))
      // Or, if multiple clients access the backend:
      //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
      .build();

  // (Receive idTokenString by HTTPS POST)

  GoogleIdToken idToken = verifier.verify(idTokenString);
  if (idToken != null) {
    Payload payload = idToken.getPayload();

    // Print user identifier
    String userId = payload.getSubject();
    System.out.println("User ID: " + userId);

    // Get profile information from payload
    String email = payload.getEmail();
    boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
    String name = (String) payload.get("name");
    String pictureUrl = (String) payload.get("picture");
    String locale = (String) payload.get("locale");
    String familyName = (String) payload.get("family_name");
    String givenName = (String) payload.get("given_name");

    // Use or store profile information
    // ...

  } else {
    System.out.println("Invalid ID token.");
  }

El método GoogleIdTokenVerifier.verify() verifica la firma de JWT, la reclamación aud, la reclamación iss y la reclamación exp.

Si necesitas validar que el token de ID representa una cuenta de organización de Google Workspace o Cloud, puedes verificar la reclamación hd si revisas el nombre de dominio que muestra el método Payload.getHostedDomain().

Llama al extremo tokeninfo

Una forma sencilla de validar una firma de token de ID para la depuración es usar el extremo tokeninfo. Llamar a este extremo implica una solicitud de red adicional que realiza la mayor parte de la validación por ti mientras pruebas la validación y la extracción de carga útil adecuadas en tu propio código. No es adecuada para su uso en código de producción, ya que las solicitudes pueden limitarse o estar sujetas a errores intermitentes.

Para validar un token de ID con el extremo tokeninfo, realiza una solicitud HTTPS POST o GET al extremo y pasa el token de ID en el parámetro id_token. Por ejemplo, para validar el token "XYZ123", realiza la siguiente solicitud GET:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

Si el token está firmado correctamente y las reclamaciones iss y exp tienen los valores esperados, obtendrás una respuesta HTTP 200, en la que el cuerpo contiene las reclamaciones de token de ID con formato JSON. Esta es una respuesta de ejemplo:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

Si necesitas validar que el token de ID representa una cuenta de Google Workspace, puedes verificar la reclamación hd, que indica el dominio alojado del usuario. Se debe usar cuando se restringe el acceso a un recurso solo a miembros de ciertos dominios. La ausencia de este reclamo indica que la cuenta no pertenece a un dominio alojado en Google Workspace.