Firebase Google Auth离线访问类型,以获得令牌刷新

5cg8jx4n  于 2023-01-21  发布在  Go
关注(0)|答案(5)|浏览(160)

我们使用firebase和google认证。我们选择Google是因为我们的应用程序会调用Google API。我们使用从firebase返回的授权有效负载中包含的access_token来授权这些API调用。但是,我们很难弄清楚如何在access_token过期后刷新它。根据Google的说法,我们应该假设access_token可能会由于各种原因过期。
因此,(据我所知)我们需要一种方法来刷新这个令牌,而不强制用户重新授权。理想情况下,我可以在请求firebase auth时请求offline access_type ...但我不知道如何做到这一点(除了再次触发firebase.authWithOAuthPopup(...),我们绝对不想这样做,因为用户会话显然仍然有效。
是否可以通过Firebase获得离线访问类型的Google oauth令牌,以便Google返回refresh_token(https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl)?使用refresh_token,我想我可以为API调用获取新的访问令牌。
我正在尝试这个,但它肯定不支持:

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显示为online。
谢谢

olmpazwi

olmpazwi1#

最大限度降低服务器端实现要求的解决方案。

**TL:DR;**使用Google Sign-In for Websites库生成授权证书。使用授权证书登录Firebase,并将离线访问交换代码发布到服务器。

客户端

客户端我通过包含以下内容实现了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>

**注意:**作用域应该是以空格分隔的所需访问作用域列表。

假设加载了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. See here for the auth2 library reference将身份验证凭据传回您的Web应用。
在应用程序的其他地方,我正在侦听Firebase auth状态的更改。

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    // navigate to logged in state
  } else {
    // navigate to login page
  }
});

服务器端

POSTofflineAccessExchangeCode(看起来像{"code": "..."})到我的服务器来交换当前认证用户的creds,其中包括一个刷新令牌。虽然客户端你可以访问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解析器是我目前正在进行的一个需要此功能的项目。

oalqel3c

oalqel3c2#

暂时解决。根据Firebase的Rob DiMarco:“不幸的是,目前还不可能通过Firebase获得谷歌OAuth刷新令牌,尽管我们已经意识到这一点,并希望加以解决。”

ecr0jaav

ecr0jaav3#

在您的客户端代码中使用不同的OAuth 2.0库,该库 * 能够 * 通过access_type=offline发送授权请求。在OAuth 2.0与Google的交互中,没有任何特定于firebase的东西可以为您获取访问令牌和刷新令牌。因此您可以依赖于单独代码来处理这些部分。当然,您需要提供作用域(s)专门用于Firebase(我相信至少是“https://www.googleapis.com/auth/freebase“),但这对任何OAuth 2.0客户端库都不是问题。

lb3vh1jj

lb3vh1jj4#

已解决:Google OAuth刷新令牌未返回有效的访问令牌
你必须在服务器上进行身份验证,然后返回一个idtoken给客户端,在服务器上通过身份验证后用firebase登录,这样你就可以在后端获得刷新令牌,将它们存储在你的数据库(从服务器)的用户身上,并使用刷新令牌重新进行身份验证。

68de4m5k

68de4m5k5#

2023年更新:现在这是可能的!如果你按照这里的说明:
https://firebase.google.com/docs/auth/extend-with-blocking-functions#accessing_a_users_identity_provider_oauth_credentials
要创建一个阻塞函数,可以获取一个刷新令牌。请参见下面的示例代码:

exports.beforeCreate = authClient.functions().beforeCreateHandler((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'google.com') {
    const refreshToken = context.credential.refreshToken;
    const uid = user.uid;
    // These will only be returned if refresh tokens credentials are included
    // (enabled by Cloud console).
    
    // TODO: Store or use your refreshToken here!
  }
});

只需确保在部署阻塞函数后注册它,并确保选择refreshToken:)

贷方:https://stackoverflow.com/a/74989323

相关问题