Autentica usuarios con Acceder con Google

Acceder con Google te ayuda a integrar rápidamente la autenticación de usuarios en tu app para Android. Los usuarios pueden usar su Cuenta de Google para acceder a tu app, dar su consentimiento y compartir la información de su perfil de forma segura con la app. La biblioteca de Credential Manager de Android de Jetpack hace que esta integración sea fluida y ofrece una experiencia coherente en todos los dispositivos Android con una sola API.

En este documento, se te guía para implementar Acceder con Google en apps para Android, cómo configurar la IU del botón de Acceder con Google y cómo configurar experiencias de registro y acceso con un solo toque optimizadas para la app. Para que la migración de dispositivos sea fluida, Acceder con Google admite el acceso automático, y su naturaleza multiplataforma en Android, iOS y plataformas web te ayuda a proporcionar acceso a tu app en cualquier dispositivo.

Para configurar Acceder con Google, sigue estos dos pasos principales:

Configura Acceder con Google como una opción para la IU de la hoja inferior del Administrador de credenciales. Esta opción se puede configurar para solicitarle automáticamente que acceda al usuario. Si implementaste llaves de acceso o contraseñas, puedes solicitar todos los tipos de credenciales relevantes de forma simultánea para que el usuario no tenga que recordar la opción que usó anteriormente para acceder.

Hoja inferior del Administrador de credenciales
Figura 1: IU de selección de credenciales de la hoja inferior del Administrador de credenciales

Agrega el botón Acceder con Google a la IU de tu app. El botón Acceder con Google ofrece una forma optimizada para que los usuarios usen sus Cuentas de Google existentes para registrarse o acceder a apps para Android. Los usuarios harán clic en el botón Acceder con Google si descartan la IU de la hoja inferior o si quieren usar su Cuenta de Google de forma explícita para registrarse y acceder. Para los desarrolladores, esto significa una integración más fácil del usuario y una reducción de los problemas durante el registro.

Animación que muestra el flujo de Acceder con Google
Figura 2: IU del botón Acceder con Google del Administrador de credenciales

En este documento, se explica cómo integrar el botón Acceder con Google y el diálogo de la hoja inferior con la API de Credential Manager con la biblioteca auxiliar de ID de Google.

Cómo configurar tu proyecto de la Consola de APIs de Google

  1. Abre tu proyecto en la Consola de APIs o crea uno si aún no tienes uno.
  2. En la página Pantalla de consentimiento de OAuth, asegúrate de que toda la información sea completa y precisa.
    1. Asegúrate de que se hayan asignado un nombre, un logotipo y una página principal de la app correctos. Estos valores se presentarán a los usuarios en la pantalla de consentimiento de Acceder con Google durante el registro y en la pantalla Apps y servicios de terceros.
    2. Asegúrate de haber especificado las URLs de la política de privacidad y las condiciones del servicio de tu app.
  3. En la página Credenciales, crea un ID de cliente de Android para tu app si aún no tienes uno. Deberás especificar el nombre de paquete de tu app y la firma SHA-1.
    1. Ve a la página Credenciales.
    2. Haz clic en Crear credenciales > ID de cliente de OAuth.
    3. Selecciona el tipo de aplicación Android.
  4. En la página Credenciales, crea un nuevo ID de cliente de "aplicación web" si aún no lo hiciste. Por ahora, puedes ignorar los campos "Orígenes de JavaScript autorizados" y "URIs de redireccionamiento autorizados". Este ID de cliente se usará para identificar tu servidor de backend cuando se comunique con los servicios de autenticación de Google.
    1. Ve a la página Credenciales.
    2. Haz clic en Crear credenciales > ID de cliente de OAuth.
    3. Selecciona el tipo de aplicación web.

Cómo declarar dependencias

En el archivo build.gradle de tu módulo, declara las dependencias con la versión más reciente del Administrador de credenciales:

dependencies {
  // ... other dependencies

  implementation "androidx.credentials:credentials:<latest version>"
  implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
  implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}

Cómo crear una instancia de una solicitud de acceso con Google

Para comenzar con la implementación, crea una instancia de una solicitud de acceso con Google. Usa GetGoogleIdOption para recuperar el token de ID de Google de un usuario.

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Primero, verifica si el usuario tiene alguna cuenta que se usó anteriormente para acceder a tu app. Para ello, llama a la API con el parámetro setFilterByAuthorizedAccounts configurado en true. Los usuarios pueden elegir entre las cuentas disponibles para acceder.

Si no hay Cuentas de Google autorizadas disponibles, se le debe solicitar al usuario que se registre con cualquiera de sus cuentas disponibles. Para ello, vuelve a llamar a la API y configura setFilterByAuthorizedAccounts como false. Obtén más información para registrarte.

Habilitar el acceso automático para los usuarios recurrentes (recomendado)

Los desarrolladores deben habilitar el acceso automático para los usuarios que se registran con su única cuenta. Esto proporciona una experiencia fluida en todos los dispositivos, en especial durante la migración de dispositivos, en la que los usuarios pueden recuperar rápidamente el acceso a su cuenta sin volver a ingresar las credenciales. Para tus usuarios, esto quita la fricción innecesaria cuando ya habían accedido con anterioridad.

Para habilitar el acceso automático, usa setAutoSelectEnabled(true). El acceso automático solo es posible cuando se cumplen los siguientes criterios:

  • Hay una sola credencial que coincide con la solicitud, que puede ser una Cuenta de Google o una contraseña, y esta credencial coincide con la cuenta predeterminada del dispositivo con Android.
  • El usuario no salió de la cuenta de forma explícita.
  • El usuario no inhabilitó el acceso automático en la configuración de su Cuenta de Google.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Recuerda controlar correctamente la salida cuando implementes el acceso automático para que los usuarios siempre puedan elegir la cuenta adecuada después de salir de tu app de forma explícita.

Establece un nonce para mejorar la seguridad

Para mejorar la seguridad de acceso y evitar ataques de repetición, agrega setNonce para incluir un nonce en cada solicitud. Obtén más información para generar un nonce.

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Crea el flujo de Acceder con Google

Los pasos para configurar un flujo de Acceder con Google son los siguientes:

  1. Crea una instancia de GetCredentialRequest y, luego, agrega el googleIdOption creado anteriormente con addCredentialOption() para recuperar las credenciales.
  2. Pasa esta solicitud a la llamada a getCredential() (Kotlin) o a getCredentialAsync() (Java) para recuperar las credenciales disponibles del usuario.
  3. Una vez que la API funcione de forma correcta, extrae el objeto CustomCredential que contiene el resultado de los datos de GoogleIdTokenCredential.
  4. El tipo de CustomCredential debe ser igual al valor de GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL. Convierte el objeto en una GoogleIdTokenCredential con el método GoogleIdTokenCredential.createFrom.
  5. Si la conversión se realiza correctamente, extrae el ID de GoogleIdTokenCredential, valóralo y autentica la credencial en tu servidor.

  6. Si la conversión falla con una GoogleIdTokenParsingException, es posible que debas actualizar la versión de la biblioteca de Acceder con Google.

  7. Detecta cualquier tipo de credencial personalizada no reconocido.

val request: GetCredentialRequest = Builder()
  .addCredentialOption(googleIdOption)
  .build()

coroutineScope.launch {
  try {
    val result = credentialManager.getCredential(
      request = request,
      context = activityContext,
    )
    handleSignIn(result)
  } catch (e: GetCredentialException) {
    handleFailure(e)
  }
}

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {

    // Passkey credential
    is PublicKeyCredential -> {
      // Share responseJson such as a GetCredentialResponse on your server to
      // validate and authenticate
      responseJson = credential.authenticationResponseJson
    }

    // Password credential
    is PasswordCredential -> {
      // Send ID and password to your server to validate and authenticate.
      val username = credential.id
      val password = credential.password
    }

    // GoogleIdToken credential
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract the ID to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
          // You can use the members of googleIdTokenCredential directly for UX
          // purposes, but don't use them to store or control access to user
          // data. For that you first need to validate the token:
          // pass googleIdTokenCredential.getIdToken() to the backend server.
          GoogleIdTokenVerifier verifier = ... // see validation instructions
          GoogleIdToken idToken = verifier.verify(idTokenString);
          // To get a stable account identifier (e.g. for storing user data),
          // use the subject ID:
          idToken.getPayload().getSubject()
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      } else {
        // Catch any unrecognized custom credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

Activa un flujo del botón de Acceder con Google

Para activar el flujo del botón de Acceder con Google, usa GetSignInWithGoogleOption en lugar de GetGoogleIdOption:

val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
  .setServerClientId(WEB_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Controla el GoogleIdTokenCredential que se muestra como se describe en el siguiente ejemplo de código.

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract id to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      }
      else -> {
        // Catch any unrecognized credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

Una vez que crees una instancia de la solicitud de Acceso con Google, inicia el flujo de autenticación de una manera similar a la que se menciona en la sección Acceder con Google.

Habilitar el registro de usuarios nuevos (recomendado)

Acceder con Google es la manera más fácil para que los usuarios creen una cuenta nueva con tu app o servicio en solo unos pasos.

Si no se encuentran credenciales guardadas (getGoogleIdOption no muestra ninguna Cuenta de Google), pídele al usuario que se registre. Primero, verifica si setFilterByAuthorizedAccounts(true) para ver si existen cuentas que se hayan usado anteriormente. Si no se encuentra ninguna, pídele al usuario que se registre con su Cuenta de Google con setFilterByAuthorizedAccounts(false).

Ejemplo:

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(WEB_CLIENT_ID)
  .build()

Una vez que crees una instancia de la solicitud de Registrarse con Google, inicia el flujo de autenticación. Si los usuarios no quieren usar Acceso con Google para registrarse, considera optimizar tu app para el autocompletado. Una vez que el usuario haya creado una cuenta, considera inscribirlo en llaves de acceso como el último paso de la creación de la cuenta.

Controla la salida

Cuando un usuario salga de tu app, llama al método clearCredentialState() de la API para borrar el estado actual de las credenciales del usuario de todos los proveedores de credenciales. Esto notificará a todos los proveedores de credenciales que se debe borrar cualquier sesión de credenciales almacenada para la app determinada.

Es posible que un proveedor de credenciales haya almacenado una sesión de credenciales activa y la use para limitar las opciones de acceso para futuras llamadas de obtención de credenciales. Por ejemplo, puede priorizar la credencial activa sobre cualquier otra credencial disponible. Cuando el usuario salga de tu app de forma explícita y para obtener las opciones de acceso integral la próxima vez, debes llamar a esta API para permitir que el proveedor borre cualquier sesión de credenciales almacenada.