0

Google OAuth 2.0 recommends the following oauth flow:

a hybrid server-side flow where a user authorizes your app on the client side using the JavaScript API client and you send a special one-time authorization code to your server. Your server exchanges this one-time-use code to acquire its own access and refresh tokens from Google for the server to be able to make its own API calls, which can be done while the user is offline.

I am trying to do exactly this but using passport.js instead. In a normal (entirely server-side) workflow, Passport expects one-time authorization code from Google in a query parameter at the redirect link (for example: /auth/google/redirect). Hence, I would expect the same redirect endpoint to work if I call it from my client (with the authorization code), instead of Google redirecting it to.

However, when I try to do that, I get the following error from Passport:

TokenError: Bad Request
    at Strategy.OAuth2Strategy.parseErrorResponse (node_modules/passport-oauth2/lib/strategy.js:358:12)
    at Strategy.OAuth2Strategy._createOAuthError (node_modules/passport-oauth2/lib/strategy.js:405:16)
    at node_modules/passport-oauth2/lib/strategy.js:175:45
    at node_modules/oauth/lib/oauth2.js:191:18
    at passBackControl (node_modules/oauth/lib/oauth2.js:132:9)
    at IncomingMessage.<anonymous> (node_modules/oauth/lib/oauth2.js:157:7)
    at IncomingMessage.emit (events.js:327:22)
    at endReadableNT (_stream_readable.js:1201:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)

Is it incorrect to expect the code sent from my client-side to work this way? What am I doing wrong?

4

1 回答 1

0

我遇到过类似的问题并已解决。

我一直在尝试使用 React-Native 应用程序和 NodeJS 服务器来实现这种行为。

在 React-Native 方面,我使用 Expo 的 AuthSession 模块。以下是代码:

let response = await AuthSession.startAsync({
    authUrl:
        `https://accounts.google.com/o/oauth2/v2/auth?` +
        `&client_id=${GOOGLE_WEB_APP_ID}` +
        `&redirect_uri=${encodeURIComponent(redirectUrl)}` +
        `&response_type=code` +
        `&access_type=offline` +
        `&prompt=consent` +
        `&scope=profile`,
    // `&scope=${encodeURIComponent('https://www.googleapis.com/auth/plus.profile.emails.read https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/contacts')}`,
});

这会返回一个一次性使用授权代码,该代码可以与 Google 交换一个如下所示的有效负载:

    {
  "accessToken": "******",
  "idToken": "****",
  "refreshToken": "******",
  "type": "success",
  "user": Object {
    "email": "**********@gmail.com",
    "familyName": "P**********n",
    "givenName": "Aa******",
    "id": "1141489**************",
    "name": "******",
    "photoUrl": "**********",
  },
}

在服务器端,我使用的是 Google OAuth 2.0 Passport Strategy。https://www.npmjs.com/package/passport-google-oauth20

但问题在于,这种策略在我的情况下并不是特别有用,因为它不使用一次性使用授权码。

作为替代,我正在查看https://github.com/shobhitsinghal624/passport-google-authcode

目前,我正在编写一个类似的模块供我自己使用,因为它似乎是一个非常小众的需求。

于 2020-05-25T18:05:12.460 回答