web-dev-qa-db-ja.com

Google :: Apis :: AuthorizationError(無許可)

Ionicフレームワークをフロントエンドとして、Ruby on Rails=バックエンドとして使用します。アプリでGmailアカウントをリンクできます。アカウントリンクは正常に機能しています。フロントエンドからserverAuthCodeを取得し、それを使用して更新トークンを取得します。は最初の試行でその更新トークンを使用してメールをフェッチできますが、数秒以内に期限切れになるか取り消されます。次の問題を取得します:

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

更新トークン自体が数秒で期限切れになるようです。誰かがそれを修正する方法について何か考えを持っていますか?

更新:

既存のコードは次のようになります。

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

参照リンク: https://github.com/google/google-api-Ruby-client/issues/296

18
MeeSN

十分なコードが投稿されていませんが、投稿されたものは間違っています。

  • linked_accountが定義されていません
  • linked_account.tokenが更新されている(または設定されている)ことはどこにも示されていません。 refresh_tokenを使用して新しいアクセストークンを取得する場合は、更新する必要があります。
  • authauth.fetch_access_token!行で未定義のようです
  • GmailService#authorization=AccessTokenではなくSignet::OAuth2::Clientを取ります。

おそらく、新しいアクセストークンを取得して古いアクセストークンを無効にするlinked_account.tokenを呼び出すまで、client.update!に有効なアクセストークンがあることが原因と考えられます。ただし、linked_accountを更新することはないため、それをリセットするコードパスを実行するまで、以降の呼び出しは失敗します。

アクセストークンの有効期限が切れている場合にのみclient.update!を呼び出す必要があり、有効期限が切れて新しいトークンを取得した場合は、その新しいトークンをlinked_account.tokenに保存する必要があります。

1
Old Pro

更新トークンでアクセストークンを更新してみましたか?エラーをキャッチして再試行できます。

このようなもの:

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

私が推測できることから、問題はこれらの2つの行にあるようです。トークンの有効期限がチェックされ、新しいトークンが生成される方法。最小限の再現可能なコードがあればそれは素晴らしいでしょう。

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

アクセストークンを取得する方法は次のとおりです。

  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

そして、このアクセストークンをあらゆる目的に使用します。それがどうなるのか、また、再現可能なバージョンのAPIを作成できるかどうかを教えてください。それは素晴らしい。

1
aks

更新トークンが機能しなくなる理由はいくつかあります。

  1. 使用しない場合、古い更新トークンは6か月後に期限切れになります。
  2. ユーザーはアプリケーションを再認証して新しいリフレッシュトークンを取得できます。両方のリフレッシュトークンが機能し、最大50個の未処理のリフレッシュトークンを取得できます。最初のトークンは機能しなくなります。
  3. ユーザーはアクセスを取り消すことができます。
  4. 2015年のWakey夏時間バグ。(それについては触れません)

Gmailとパスワードのリセット。

これは主にパスワードのリセットによるものです。 OAuth gmailスコープによる付与は、ユーザーがパスワードを変更すると取り消されます。

参照 自動OAuthパスワード変更時の2.0トークンの取り消し

通常、ユーザーはいつでも許可を取り消すことができます。このケースを適切に処理し、提供された機能を引き続き使用したい場合は再認証する必要があることをユーザーに警告できるはずです。

あなたは多くのテストを行ってきましたが、最新の更新トークンを保存していますか?そうでない場合は、古いリフレッシュトークンを使用している可能性があり、動作しなくなります。 (2番)

0
DaImTo

refresh token期限切れになることは実際には誤解です。実際のシーンでは、サーバーが有効期間の短いアクセストークンと有効期間の長い更新トークンを発行しています。したがって、実際に起こることは、長命の更新トークンを使用してアクセストークンを取り戻すことができるということですが、はい、新しい更新トークンを要求する必要があります(期限切れになるためです!)。例えば;更新トークンは、期限切れにならないように扱うことができます。ただし、ユーザーが更新トークンを取り消す場合に備えて、サインイン時に新しいトークンを確認してください。このシナリオでは、Googleはサインイン時に新しい更新トークンを提供するため、更新トークンを更新します。

これで、条件は、ユーザーがアプリケーションへのアクセスを取り消すことになります。この場合、refresh tokenは期限切れになります(または、実際には無許可になると言わなければなりません)。したがって、それがあなたのケースのシナリオである場合、アプリケーションのアクセス権の取り消しを回避することを考える必要があります。

それをよりよく理解するために、この documentOAuth 2.0のドキュメント を参照してください。

0
Sumit Panse

私の場合、youtube pload api raiseのみ

Unauthorized (Google::Apis::AuthorizationError)

リスト動画のような他のapiはうまく機能します

それは私が新しいグーグルアカウントを使って、アップビデオを持っていないからです

私は手動でYouTubeウェブでビデオをアップし、YouTubeは「チャンネル」を作成する必要があります

そして、私は再びyoutube up apiを試します、それはうまくいきます

私はYouTubeがアップするチャンネルを持っているからだと思います

0
chikadance