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
十分なコードが投稿されていませんが、投稿されたものは間違っています。
linked_account
が定義されていませんlinked_account.token
が更新されている(または設定されている)ことはどこにも示されていません。 refresh_token
を使用して新しいアクセストークンを取得する場合は、更新する必要があります。auth
はauth.fetch_access_token!
行で未定義のようですGmailService#authorization=
はAccessToken
ではなくSignet::OAuth2::Client
を取ります。おそらく、新しいアクセストークンを取得して古いアクセストークンを無効にするlinked_account.token
を呼び出すまで、client.update!
に有効なアクセストークンがあることが原因と考えられます。ただし、linked_account
を更新することはないため、それをリセットするコードパスを実行するまで、以降の呼び出しは失敗します。
アクセストークンの有効期限が切れている場合にのみclient.update!
を呼び出す必要があり、有効期限が切れて新しいトークンを取得した場合は、その新しいトークンをlinked_account.token
に保存する必要があります。
更新トークンでアクセストークンを更新してみましたか?エラーをキャッチして再試行できます。
このようなもの:
begin
gmail.list_user_messages(linked_account[:uid], q: "#{query}")
rescue Google::Apis::AuthorizationError => exception
client.refresh!
retry
end
私が推測できることから、問題はこれらの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を作成できるかどうかを教えてください。それは素晴らしい。
更新トークンが機能しなくなる理由はいくつかあります。
Gmailとパスワードのリセット。
これは主にパスワードのリセットによるものです。 OAuth gmailスコープによる付与は、ユーザーがパスワードを変更すると取り消されます。
参照 自動OAuthパスワード変更時の2.0トークンの取り消し
通常、ユーザーはいつでも許可を取り消すことができます。このケースを適切に処理し、提供された機能を引き続き使用したい場合は再認証する必要があることをユーザーに警告できるはずです。
あなたは多くのテストを行ってきましたが、最新の更新トークンを保存していますか?そうでない場合は、古いリフレッシュトークンを使用している可能性があり、動作しなくなります。 (2番)
refresh token
期限切れになることは実際には誤解です。実際のシーンでは、サーバーが有効期間の短いアクセストークンと有効期間の長い更新トークンを発行しています。したがって、実際に起こることは、長命の更新トークンを使用してアクセストークンを取り戻すことができるということですが、はい、新しい更新トークンを要求する必要があります(期限切れになるためです!)。例えば;更新トークンは、期限切れにならないように扱うことができます。ただし、ユーザーが更新トークンを取り消す場合に備えて、サインイン時に新しいトークンを確認してください。このシナリオでは、Googleはサインイン時に新しい更新トークンを提供するため、更新トークンを更新します。
これで、条件は、ユーザーがアプリケーションへのアクセスを取り消すことになります。この場合、refresh token
は期限切れになります(または、実際には無許可になると言わなければなりません)。したがって、それがあなたのケースのシナリオである場合、アプリケーションのアクセス権の取り消しを回避することを考える必要があります。
それをよりよく理解するために、この document や OAuth 2.0のドキュメント を参照してください。
私の場合、youtube pload api raiseのみ
Unauthorized (Google::Apis::AuthorizationError)
リスト動画のような他のapiはうまく機能します
それは私が新しいグーグルアカウントを使って、アップビデオを持っていないからです
私は手動でYouTubeウェブでビデオをアップし、YouTubeは「チャンネル」を作成する必要があります
そして、私は再びyoutube up apiを試します、それはうまくいきます
私はYouTubeがアップするチャンネルを持っているからだと思います