Cómo obtener el código de autorización de Google una sola vez

Tengo problemas para obtener un código de autorización único de Google. Estoy intentando obtener el código de autorización de un cliente de Android para poder enviarlo a mi backend de Rails (cliente web).

En mi consola de Google Cloud Developer, tengo una aplicación con dos ID de cliente:

  1. ID de cliente para la aplicación web (para mi backend de rieles)

  2. ID de cliente para la aplicación de Android (para mi cliente android). El SHA1 utilizado es de ~ / .android / debug.keystore

Supongamos que el ID de cliente de aplicaciones web es 12345.apps.googleusercontent.com

Supongamos que el ID del cliente Android es 67890.apps.googleusercontent.com

Este es parte de mi código:

 private final static String WEB_CLIENT_ID = "12345.apps.googleusercontent.com"; private final static String GOOGLE_CALENDAR_API_SCOPE = "audience:server:client_id:" + WEB_CLIENT_ID; private void getAndUseAuthToken(final String email) { AsyncTask task = new AsyncTask<String, Void, String>() { @Override protected String doInBackground(String... emails) { try { return GoogleAuthUtil.getToken(AddExternalCalendarsActivity.this, emails[0], GOOGLE_CALENDAR_API_SCOPE); } catch (UserRecoverableAuthException e) { startActivityForResult(e.getIntent(), IntentConstants.REQUEST_GOOGLE_AUTHORIZATION); } catch (IOException e) { e.printStackTrace(); } catch (GoogleAuthException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(String authToken) { if (authToken != null) { saveTokenAndGetCalendars(email, authToken); } } }; String[] emails = new String[1]; emails[0] = email; task.execute(emails); } 

Algunas notas adicionales

  • Estoy golpeando la excepción de GoogleAuth y recibir "Desconocido" como el detalle del mensaje

  • No puedo agregar miembros adicionales a los permisos de Google Cloud Console para este proyecto: al agregar un nuevo miembro, aparece un mensaje emergente con "Error de servidor. He enviado comentarios a Google dos veces.

  • Me refiero a esta documentación . Observe la siguiente cita. Por "fijo", ¿están diciendo que no necesito prepagar audiencia: server: client_id en mi GOOGLE_CALENDAR_API_SCOPE variable? He intentado tanto con y sin y todavía obtener la misma excepción GoogleAuthException.

En esta situación, la aplicación de Android puede llamar al método GoogleAuthUtil.getToken () en nombre de cualquiera de las cuentas de Google del dispositivo y con un valor de argumento de ámbito de audiencia: server: client_id: 9414861317621.apps.googleusercontent.com. El prefijo público: server: client_id: es fijo, y el resto de la cadena del ámbito es el ID del cliente del componente web.

  • Si utilizo este ámbito, puedo autenticarme con google desde el dispositivo. Sin embargo, la documentación que he leído sugiere que necesito utilizar el ID de cliente web de servidor (que está en el mismo proyecto de consola de Google que el ID de cliente de android) en el ámbito para que el servidor toque la API de google en nombre de El usuario que lo autorizó en el cliente android:

    private final static String GOOGLE_CALENDAR_API_SCOPE = "oauth2:https://www.googleapis.com/auth/calendar";

ACTUALIZACIÓN 1

Originalmente añadí en respuesta: La razón de mi primer problema – Estoy golpeando la excepción GoogleAuthException y recibir "Desconocido" como el detalle del mensaje – fue un error que hice al agregar la identificación del cliente android en la consola de la nube. El SHA1 era correcto pero no escribí correctamente el nombre del paquete. He utilizado com.company.app cuando mi paquete android es en realidad com.company.android.app. El código en la pregunta original funciona bien. Sólo asegúrate de tener todos los clientes necesarios en tu proyecto de Google Cloud Console.

Pero todavía existe otro problema. Cuando envío el token de autorización de una sola vez devuelto de GoogleAuthUtil.getToken () al backend de Rails, y luego intento cambiarlo por un access_token y refresh_token, obtengo el siguiente:

 Signet::AuthorizationError: Authorization failed. Server message: { "error" : "invalid_grant" } 

Esta documentación de google y varias publicaciones de SO sugieren que necesito establecer access_type=offline . Pero creo que es cuando se solicita el código de autorización de una sola vez y el acceso sin conexión desde un servidor Web. Estoy intentando solicitar el código de autorización única de un cliente de Android y enviarlo al servidor web.

¿Es esto posible con GoogleAuthUtil.getToken () ?

ACTUALIZAR 2

El inicio de sesión de Google Plus debe estar en el ámbito aunque solo intentes acceder al calendario:

 private final static String GOOGLE_CALENDAR_API_SCOPE = "oauth2:server:client_id:" + WEB_CLIENT_ID + ":api_scope:https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/calendar"; 

Este post de SO fue útil. Además, la documentación de identidad de Cross Client de Google indica:

[Nota: Esta política se está desarrollando gradualmente. Por el momento, cuando los tokens de acceso están involucrados, sólo se aplica cuando los ámbitos solicitados incluyen https://www.googleapis.com/auth/plus.login.]

Resumiré en una respuesta si el intercambio simbólico funciona en el backend de Rails.

Dos cosas resolvieron esto para mí:

  1. Asegúrese de que los ID de cliente de Android y Web se configuran correctamente en el mismo proyecto de Google Cloud Console.

  2. Utilice el alcance correcto. El inicio de sesión adicional es necesario incluso si solo accedes al api del calendario:

    // el id del servidor web que está intercambiando el código de autenticación para los tokens de acceso y actualización

    Private final static String WEB_CLIENT_ID = "12345.apps.googleusercontent.com"; Private final static String GOOGLE_CALENDAR_API_SCOPE = "oauth2: servidor: id_cliente:" + WEB_CLIENT_ID + ": api_scope: https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/calendar " ;

Esto es lo que he hecho:

 final String authToken = GoogleAuthUtil.getTokenWithNotification (this.context, account.name, "oauth2:" + AuthUtils.profileScope, new Bundle (), Contract.authority, new Bundle ()); 

Pero usted getToken llano debe trabajar iguales para una actividad del primero plano.

Tome este símbolo, enviarlo al servidor de una manera que puede utilizar como un encabezado HTTP (a través de HTTPS). Siempre y cuando el ámbito del servidor sea un subconjunto del ámbito utilizado para adquirir el token, no debería tener ningún problema. El servidor utiliza la identificación del servidor y el cliente android utiliza la identificación del cliente android.

Deberá establecer su alcance en:

 oauth2:https://www.googleapis.com/auth/calendar 

o

 oauth2:https://www.googleapis.com/auth/calendar.readonly 

Consulta la página https://developers.google.com/google-apps/calendar/auth.

Edit: OK Veo lo que estás tratando de hacer. El valor del ámbito es una lista separada por espacios, por lo que es probable que tenga que añadir audiencia: server: client_id: a su ámbito de aplicación como:

 "oauth2:https://www.googleapis.com/auth/calendar audience:server:client_id:12345-your-web-component-client-id" 
  • No se pueden enviar datos de JSON desde Android al servidor ROR
  • MultipartEntityBuilder para enviar imágenes al servidor de carril
  • ¿Cómo puedo verificar la facturación de Android en la aplicación con un servidor con Ruby?
  • ¿Qué puedo usar para permitir que una aplicación de Android se comunique con una aplicación de rails
  • Authenticity_token en Rails + Android
  • ¿Qué método de autenticación debo usar con la gema Sorcery usando una aplicación móvil?
  • Iniciar el entorno de desarrollo de rails en android
  • Convierta la aplicación Ruby on Rails en la aplicación Android PhoneGap nativa
  • Dispositivo de Android de acceso de host local en la computadora portátil
  • Cordova App en Android usando SSL enviando multipart / form-data causes Error de la aplicación de rack: # <EOFError: cuerpo de contenido incorrecto>
  • Tipo de entrada = número no es posible insertar números negativos en el teléfono móvil
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.