快速概述:我有一个 ruby 应用程序,它每晚运行并使用用户的谷歌日历做一些事情。用户已经通过单独的 react 应用程序授予访问权限。我无法让 ruby 应用程序使用来自 react 应用程序的授权代码访问用户的日历。
详细信息:我有一个 React 前端,可以使用 gapi 登录用户,然后将用户登录到 Firebase。以下是我配置 gapi obj 的方法:
this.auth2 = await loadAuth2WithProps({
apiKey: config.apiKey, // from firebase
clientId: config.clientId, // from gcp
// ....
access_type: "offline", // so we get get authorization code
})
这里是登录:
doSignInWithGoogle = async () => {
const googleUser = await this.auth2.signIn();
const token = googleUser.getAuthResponse().id_token;
const credential = app.auth.GoogleAuthProvider.credential(token);
return this.auth.signInWithCredential(credential);
};
用户的下一步是授予应用对其日历的离线访问权限:
doConnectGoogleCalendar = async () => {
const params = {scope:scopes};
const result = await this.auth2.grantOfflineAccess(params);
console.log(result.code); // logs: "4/ygFsjdK....."
};
此时,前端具有可以传递给服务器端应用程序以交换访问和刷新令牌的授权代码。我一直无法找到一种使用用户提供的身份验证代码来调用可用范围的好方法。这就是我配置 oauth 客户端的方式:
auth_client = Google::APIClient::ClientSecrets.load(
File.join(Rails.root,'config','client_secrets.json') // downloaded from GCP
).to_authorization
^ 我在后端使用与前端相同的 GCP 凭据。它是一种“OAuth 2.0 客户端 ID”类型的凭证。我不确定这是否是好习惯。另外,我是否需要定义与前端相同的配置(如 access_type 和 scope)?
接下来我按照文档所说的来获取访问和刷新令牌(单击 Ruby):
auth_client.code = authorization_code_from_frontend
auth_client.fetch_access_token!
---------
Signet::AuthorizationError (Authorization failed. Server message:)
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
在设置可以处理对用户授予范围的脱机访问的单独后端应用程序时,我是否缺少一些东西?这些库上有很多不同的信息,但我无法将其提炼成有用的东西。
更新 我发现这个页面描述了我在其他任何地方都没有找到的“一次性代码流程”,这是我浏览过的所有文档。它确实回答了我上面的一个小问题:是的,您可以使用与后端 Web 应用程序相同的客户端密码。(请参阅底部的完整示例,他们就是这样做的)。我会更多地探索它,看看是否可以解决我更大的问题。还将更新标题以包含一次性代码流。