ruby on rails - Google:: Apis:: AuthorizationError(no autorizado)




ruby-on-rails google-oauth (4)

Estamos creando una aplicación con Ionic Framework como front-end y Ruby on Rails como back-end. Podemos vincular la cuenta de Gmail en nuestra aplicación. La vinculación de cuentas funciona bien, obtenemos serverAuthCode desde el front-end y luego utilizamos el token de actualización y podemos recuperar los correos electrónicos con ese token de actualización al primer intento. Pero en unos segundos, se vence o se revoca. Consiguiendo el siguiente problema:

Signet::AuthorizationError (Authorization failed.  Server message:
{
  "error" : "invalid_grant",
  "error_description" : "Token has been expired or revoked."
})

Parece que, el token de actualización en sí está expirando en segundos. ¿Alguien tiene alguna idea acerca de cómo solucionarlo?

Actualizar:

El código existente se ve así:

class User   
  def authentication(linked_account)
    client = Signet::OAuth2::Client.new(
    authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
    token_credential_uri: Rails.application.secrets.token_credential_uri,
    client_id: Rails.application.secrets.google_client_id,
    client_secret: Rails.application.secrets.google_client_secret,
    scope: 'https://www.googleapis.com/auth/gmail.readonly, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile',
    redirect_uri: Rails.application.secrets.redirect_uri,
    refresh_token: linked_account[:refresh_token]
  )

  client.update!(access_token: linked_account.token, expires_at: linked_account.expires_at)
  return  AccessToken.new(linked_account.token) unless client.expired?
  auth.fetch_access_token! 
 end

 def get_email(linked_account)
   auth = authentication(linked_account)
   gmail = Google::Apis::GmailV1::GmailService.new
   gmail.client_options.application_name = User::APPLICATION_NAME
   gmail.authorization = AccessToken.new(linked_account.token)
   query = "(is:inbox OR is:sent)"
   gmail.list_user_messages(linked_account[:uid], q: "#{query}")
   ## Getting error over here ^^
  end
end // class end 

class AccessToken
  attr_reader :token
  def initialize(token)
    @token = token
  end

  def apply!(headers)
    headers['Authorization'] = "Bearer #{@token}"
  end
end

Enlace de referencia: https://github.com/google/google-api-ruby-client/issues/296


¿Ha intentado actualizar el token de acceso con el token de actualización? Usted puede atrapar el error y volver a intentarlo.

Algo como esto:

begin
  gmail.list_user_messages(linked_account[:uid], q: "#{query}")
rescue Google::Apis::AuthorizationError => exception
  client.refresh!
  retry
end

Hay varias razones por las que un token de actualización dejaría de funcionar.

  1. Se pone a los tokens de actualización viejos caducan después de seis meses si no se utilizan.
  2. Un usuario puede volver a declarar su aplicación y obtener un nuevo token de actualización. Ambos tokens de actualización funcionarán. Puede tener un máximo de cincuenta tokens de actualización pendientes y el primero dejará de funcionar.
  3. El usuario puede revocar su acceso.
  4. Error de horario de verano de Wakey de 2015 (no hablaremos de eso)

Gmail y restablecer contraseña.

Esto es principalmente debido a un restablecimiento de contraseña. Las concesiones de OAuth con los ámbitos de gmail se revocan cuando un usuario cambia su contraseña.

Ver la revocación automática del token OAuth 2.0 al cambiar la contraseña

En general, los usuarios pueden revocar subvenciones en cualquier momento. Debe poder manejar ese caso con gracia y alertar al usuario de que necesita volver a autorizar si desea continuar usando la funcionalidad provista.

¿Has estado haciendo muchas pruebas que supongo que estás guardando el token de actualización más reciente? Si no, entonces puedes estar usando tokens de actualización viejos y dejarán de funcionar. (Número 2)


No se ha publicado suficiente código, pero lo que se publica parece incorrecto.

  • linked_account no está definido
  • En ninguna parte se muestra que el linked_account.token se actualice (o establezca). Debe actualizarse cuando se utiliza el refresh_token para obtener un nuevo token de acceso.
  • auth Parece que auth no está definido en la línea auth.fetch_access_token!
  • GmailService#authorization= toma un Signet::OAuth2::Client no un AccessToken .

Probablemente, lo que está sucediendo es que tiene un token de acceso válido en linked_account.token hasta que llame a client.update! , que recupera un nuevo token de acceso e invalida el anterior. Pero como nunca actualiza el linked_account , las llamadas futuras fallarán hasta que pase por la ruta del código que lo restablece.

Solo necesitas llamar a client.update! Si el token de acceso ha caducado, y si ha caducado y obtiene uno nuevo, debe almacenar ese nuevo en linked_account.token .


Por lo que puedo adivinar, el problema parece estar en estas dos líneas. La forma en que se verifica la caducidad del token y el nuevo token se genera. Sería genial si hay un código mínimo reproducible.

return  AccessToken.new(linked_account.token) unless client.expired?
auth.fetch_access_token! 

Así es como obtengo mi token de acceso:

  def self.access_token(refresh_token)
    Cache.fetch(refresh_token, expires_in: 60.minutes) do
      url = GoogleService::TOKEN_CREDENTIAL_URI
      # p.s. TOKEN_CREDENTIAL_URI = 'https://www.googleapis.com/oauth2/v4/token'
      _, response = Request.post(
        url,
        payload: {
          "client_id": GoogleService::CLIENT_ID,
          "client_secret": GoogleService::CLIENT_SECRET,
          "refresh_token": refresh_token,
          "grant_type": "refresh_token"
        }
      )
      response['access_token']
    end
  end

Y luego use este token de acceso para cualquier propósito. Avíseme cómo va y también si puede crear una versión reproducible de la API. Eso será grandioso.





google-client