Firebase Google 离线授权 access_type 以获得令牌刷新
Firebase Google Auth offline access_type in order to get a token refresh
我们正在使用具有 google 身份验证的 firebase。我们选择 Google 是因为我们的应用程序进行 Google API 调用。我们使用 access_token 授权这些 api 调用,授权负载中包含来自 firebase return 的 access_token。但是,我们无法弄清楚如何在 access_token 过期后刷新它。根据 Google,我们应该假设 access_token 可能会因各种原因过期。
因此,(据我了解)我们需要一种方法来刷新此令牌,而无需强制用户重新授权。理想情况下,我可以在请求 firebase 身份验证时请求离线 access_type ......但我不知道该怎么做(除了再次触发 firebase.authWithOAuthPopup(...) ,我们绝对不希望作为用户会话显然仍然有效。
是否可以通过 Firebase 获得离线 access_type Google oauth 令牌,以便 Google 将 return refresh_token (https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl)?有了 refresh_token,我想我可以为 api 调用一个新的 access_token。
我正在尝试这个,但它绝对不受支持:
this.firebase.authWithOAuthPopup("google", this.authenticateGoogle.bind(this), {
access_type: 'offline', <-- not passed to Google
scope: 'https://www.googleapis.com/auth/userinfo.profile, https://www.googleapis.com/auth/devstorage.read_write'
});
对 https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=abcd 的所有调用都显示 access_type 在线。
谢谢
暂时解决。根据来自 Firebase 的 Rob DiMarco:"Unfortunately, it is not currently possible to get a Google OAuth refresh token via Firebase, though it's something we're aware of and hope to fix."
在您的客户端代码中使用不同的 OAuth 2.0 库, 能够使用 access_type=offline
发送授权请求。在与 Google 的 OAuth 2.0 交互中,没有任何特定于 firebase 的内容可以为您提供访问令牌和刷新令牌,因此您可以为该部分依赖单独的代码。当然,您需要专门为 Firebase 提供范围(我相信至少是“https://www.googleapis.com/auth/freebase”),但这对任何 OAuth 2.0 客户端库来说都不是问题。
一种最大限度地减少服务器端实施要求的解决方案。
TL:DR; 使用 Google Sign-In for Websites 库生成身份验证凭据。使用身份验证凭据登录 Firebase,然后 post 离线访问交换代码到您的服务器。
客户端
客户端我通过包含以下内容实现了 Google Sign-In for Websites:
<script src="https://apis.google.com/js/platform.js?onload=loadAuth2" async defer></script>
<script>
function loadAuth2 () {
gapi.load('auth2', function() {
gapi.auth2.init({
client_id: 'your firebase Web client ID',
cookie_policy: 'single_host_origin',
scope: 'profile ...'
});
});
}
</script>
注意:范围应该是您需要的访问范围的space分隔列表。
假设加载了 Firebase,我的登录点击处理程序是:
<script>
function login() {
const auth = gapi.auth2.getAuthInstance();
auth.then(() => {
auth.grantOfflineAccess({
'redirect_uri': 'postmessage',
'prompt': 'concent',
'approval_prompt': 'force',
}).then(offlineAccessExchangeCode => {
// send offline access exchange code to server ...
const authResp = auth.currentUser.get().getAuthResponse();
const credential = firebase.auth.GoogleAuthProvider.credential(authResp.id_token);
return firebase.auth().signInWithCredential(credential);
}).then(user => {
// do the thing kid!
});
});
}
</script>
使用 'redirect_uri': 'postmessage'
调用 auth.grantOfflineAccess
会导致 Google auth2
库通过 window.postMessage
将身份验证凭据传回您的 Web 应用程序。 See here for the auth2
library reference.
在我的应用程序的其他地方,我正在监听 Firebase 身份验证状态的变化。
firebase.auth().onAuthStateChanged(user => {
if (user) {
// navigate to logged in state
} else {
// navigate to login page
}
});
服务器端
我 POST
offlineAccessExchangeCode
(看起来像 {"code": "..."}
)到我的服务器,为当前经过身份验证的用户交换信用,其中包括刷新令牌。虽然客户端你可以访问 firebase.auth().currentUser.refreshToken
这个令牌对我不起作用(也许有人可以告诉我我在这里弄错了 :D)
我在 Python 中的服务器端代码如下。请注意,Google SDK 是为大多数 Google 服务自动生成的,因此以下代码应该可以轻松翻译成它们支持的任何语言。
from oauth2client import client
// ...
// assuming flask
@app.route("/google/auth/exchange", methods=['POST'])
def google_auth_exchange():
auth_code = request.get_json()['code']
credentials = client.credentials_from_clientsecrets_and_code(
'config/client_secret.json', ['profile', '...'], auth_code)
print(credentials.refresh_token)
差不多就这些了。如果您需要离线访问,我会假设您有一个服务器或一些服务器端代码,因此希望实现一个路由离理想的解决方案不远。
排序
注意: GCLID 解析器是我目前正在处理的一个项目,需要它。
已解决:Google OAuth Refresh Tokens not returning Valid Access Tokens
你必须在服务器上处理身份验证,然后return一个idtoken给客户端,在服务器上通过身份验证后使用firebase登录。这样您就可以在后端获取刷新令牌,将它们存储在您数据库中的用户(来自服务器)上并使用该刷新令牌重新进行身份验证。
我们正在使用具有 google 身份验证的 firebase。我们选择 Google 是因为我们的应用程序进行 Google API 调用。我们使用 access_token 授权这些 api 调用,授权负载中包含来自 firebase return 的 access_token。但是,我们无法弄清楚如何在 access_token 过期后刷新它。根据 Google,我们应该假设 access_token 可能会因各种原因过期。
因此,(据我了解)我们需要一种方法来刷新此令牌,而无需强制用户重新授权。理想情况下,我可以在请求 firebase 身份验证时请求离线 access_type ......但我不知道该怎么做(除了再次触发 firebase.authWithOAuthPopup(...) ,我们绝对不希望作为用户会话显然仍然有效。
是否可以通过 Firebase 获得离线 access_type Google oauth 令牌,以便 Google 将 return refresh_token (https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl)?有了 refresh_token,我想我可以为 api 调用一个新的 access_token。
我正在尝试这个,但它绝对不受支持:
this.firebase.authWithOAuthPopup("google", this.authenticateGoogle.bind(this), {
access_type: 'offline', <-- not passed to Google
scope: 'https://www.googleapis.com/auth/userinfo.profile, https://www.googleapis.com/auth/devstorage.read_write'
});
对 https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=abcd 的所有调用都显示 access_type 在线。
谢谢
暂时解决。根据来自 Firebase 的 Rob DiMarco:"Unfortunately, it is not currently possible to get a Google OAuth refresh token via Firebase, though it's something we're aware of and hope to fix."
在您的客户端代码中使用不同的 OAuth 2.0 库, 能够使用 access_type=offline
发送授权请求。在与 Google 的 OAuth 2.0 交互中,没有任何特定于 firebase 的内容可以为您提供访问令牌和刷新令牌,因此您可以为该部分依赖单独的代码。当然,您需要专门为 Firebase 提供范围(我相信至少是“https://www.googleapis.com/auth/freebase”),但这对任何 OAuth 2.0 客户端库来说都不是问题。
一种最大限度地减少服务器端实施要求的解决方案。
TL:DR; 使用 Google Sign-In for Websites 库生成身份验证凭据。使用身份验证凭据登录 Firebase,然后 post 离线访问交换代码到您的服务器。
客户端
客户端我通过包含以下内容实现了 Google Sign-In for Websites:
<script src="https://apis.google.com/js/platform.js?onload=loadAuth2" async defer></script>
<script>
function loadAuth2 () {
gapi.load('auth2', function() {
gapi.auth2.init({
client_id: 'your firebase Web client ID',
cookie_policy: 'single_host_origin',
scope: 'profile ...'
});
});
}
</script>
注意:范围应该是您需要的访问范围的space分隔列表。
假设加载了 Firebase,我的登录点击处理程序是:
<script>
function login() {
const auth = gapi.auth2.getAuthInstance();
auth.then(() => {
auth.grantOfflineAccess({
'redirect_uri': 'postmessage',
'prompt': 'concent',
'approval_prompt': 'force',
}).then(offlineAccessExchangeCode => {
// send offline access exchange code to server ...
const authResp = auth.currentUser.get().getAuthResponse();
const credential = firebase.auth.GoogleAuthProvider.credential(authResp.id_token);
return firebase.auth().signInWithCredential(credential);
}).then(user => {
// do the thing kid!
});
});
}
</script>
使用 'redirect_uri': 'postmessage'
调用 auth.grantOfflineAccess
会导致 Google auth2
库通过 window.postMessage
将身份验证凭据传回您的 Web 应用程序。 See here for the auth2
library reference.
在我的应用程序的其他地方,我正在监听 Firebase 身份验证状态的变化。
firebase.auth().onAuthStateChanged(user => {
if (user) {
// navigate to logged in state
} else {
// navigate to login page
}
});
服务器端
我 POST
offlineAccessExchangeCode
(看起来像 {"code": "..."}
)到我的服务器,为当前经过身份验证的用户交换信用,其中包括刷新令牌。虽然客户端你可以访问 firebase.auth().currentUser.refreshToken
这个令牌对我不起作用(也许有人可以告诉我我在这里弄错了 :D)
我在 Python 中的服务器端代码如下。请注意,Google SDK 是为大多数 Google 服务自动生成的,因此以下代码应该可以轻松翻译成它们支持的任何语言。
from oauth2client import client
// ...
// assuming flask
@app.route("/google/auth/exchange", methods=['POST'])
def google_auth_exchange():
auth_code = request.get_json()['code']
credentials = client.credentials_from_clientsecrets_and_code(
'config/client_secret.json', ['profile', '...'], auth_code)
print(credentials.refresh_token)
差不多就这些了。如果您需要离线访问,我会假设您有一个服务器或一些服务器端代码,因此希望实现一个路由离理想的解决方案不远。
排序
注意: GCLID 解析器是我目前正在处理的一个项目,需要它。
已解决:Google OAuth Refresh Tokens not returning Valid Access Tokens
你必须在服务器上处理身份验证,然后return一个idtoken给客户端,在服务器上通过身份验证后使用firebase登录。这样您就可以在后端获取刷新令牌,将它们存储在您数据库中的用户(来自服务器)上并使用该刷新令牌重新进行身份验证。