【问题标题】:Using refresh_token for Google OAuth 2.0 returns http 400 bad request对 Google OAuth 2.0 使用 refresh_token 会返回 http 400 错误请求
【发布时间】:2013-09-20 03:32:28
【问题描述】:

我正在为连接到 Google Drive 的应用使用 server-side flow 验证。

我能够检索访问代码并交换 access_token 和用户信息。然后我坚持刷新令牌。因此,我可以确认 client_id 和 client_secret 是正确的,但是当我使用 refresh_token 获取新的 access_token 时,我得到了 400 响应。这是详细信息,我记录了初始令牌请求的响应,并且可以确认存储到数据库中的 refresh_token 与 Google 响应中的匹配。

但是当我尝试使用 refresh_token(以编程方式和 httpie)时,我得到了下面的响应。为什么?

 % http --verbose POST https://accounts.google.com/o/oauth2/token Content-Type:application/x-www-form-urlencoded refresh_token=1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc client_id=XXXX client_secret=XXXX grant_type=refresh_token                              
POST /o/oauth2/token HTTP/1.1
Content-Length: 198
Host: accounts.google.com
b'Accept': application/json
b'Accept-Encoding': gzip, deflate, compress
b'Content-Type': application/x-www-form-urlencoded
b'User-Agent': HTTPie/0.6.0

{"refresh_token": "1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc", "client_id": "XXXX", "client_secret": "XXXX", "grant_type": "refresh_token"}

HTTP/1.1 400 Bad Request
Alternate-Protocol: 443:quic
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json
Date: Mon, 16 Sep 2013 03:42:06 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: GSE
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

{
    "error": "invalid_request"
}

这是我的 Web 应用程序为该特定用户第一次登录时的日志输出,并且我保留了 refresh_token:

[debug] application - retrieved authentication code, proceeding to get token and user info
[debug] application - successfully parsed user and token: GoogleOAuthPacket(User(117397424875078935066,XXXX,XXXX,XXXX,https://lh6.googleusercontent.com/-lbSmIO8BHMA/AAAAAAAAAAI/AAAAAAAAAAA/6ncAxM6DQuM/photo.jpg,1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc),ya29.AHES6ZT0Mn0t7zWDJW-rU6c4eEnCr76MuP14hkLSC60lX0Ve7tGrbA,3600)
[debug] application - response for token request was: {
  "access_token" : "ya29.AHES6ZT0Mn0t7zWDJW-rU6c4eEnCr76MuP14hkLSC60lX0Ve7tGrbA",
  "token_type" : "Bearer",
  "expires_in" : 3600,
  "id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6IjZhODc3Mzc3MGFmNTkyMWM5OWZjMWRmYzVmN2U3NTA2YTFjOTQyZDUifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE3Mzk3NDI0ODc1MDc4OTM1MDY2IiwiYXRfaGFzaCI6Ijk0dENwbzlxNzhUYXFPOWgwWkI3dHciLCJoZCI6Im15bWFpbC5sYXVzZC5uZXQiLCJlbWFpbCI6InNjb2xpbmNydTAwMUBteW1haWwubGF1c2QubmV0IiwiYXpwIjoiNjQyMzAxMzYzNDQ0LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiYXVkIjoiNjQyMzAxMzYzNDQ0LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxMzc5Mjk5NDQwLCJleHAiOjEzNzkzMDMzNDB9.f5lBChQCxSfNfTWqSm-uR0ueoq78w2JlJOg3zFG-Wpav8Jx6ypwshcXCA0EQjFlAckBaQ_kA1uUpToidg5nGa3B-0ftMLnuGLnO-J65zyEYyMjo4Y3wFezpy9toHOk_8rPIzZ8_jzpuLKlxuqMnz0EdK-3Mik0p6pSbkZgX8lww",
  "refresh_token" : "1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc"
}
[debug] application - response for user request was: {
  "sub" : "117397424875078935066",
  "name" : "XXXX",
  "given_name" : "XXXXX",
  "family_name" : "XXXX",
  "picture" : "https://lh6.googleusercontent.com/-lbSmIO8BHMA/AAAAAAAAAAI/AAAAAAAAAAA/6ncAxM6DQuM/photo.jpg",
  "email" : "XXXX",
  "email_verified" : true,
  "hd" : "XXXX"
}
[debug] application - user User(117397424875078935066,XXXX, XXXX,XXXX,https://lh6.googleusercontent.com/-lbSmIO8BHMA/AAAAAAAAAAI/AAAAAAAAAAA/6ncAxM6DQuM/photo.jpg,1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc) not found, proceeding to save in database
[debug] application - successfully persisted user, proceeding to save token to cache

【问题讨论】:

    标签: oauth google-oauth


    【解决方案1】:

    好的,我想通了。这就是 Google OAauth 网站所说的发布请求需要的样子:

    POST /o/oauth2/token HTTP/1.1
    Host: accounts.google.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=8819981768.apps.googleusercontent.com&
    client_secret={client_secret}&
    refresh_token=1/6BMfW9j53gdGImsiyUH5kU5RsR4zwI9lUVX-tqf8JXQ&
    grant_type=refresh_token
    

    如果我将我的 httpie 更改为使用 --form 开关而不是添加 ContentType 标头,那么我确实会得到一个访问令牌:

     % http --verbose --form POST https://accounts.google.com/o/oauth2/token refresh_token=1/nJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc client_id=XXXX client_secret=XXXX grant_type=refresh_token                                                                       POST /o/oauth2/token HTTP/1.1
    Content-Length: 175
    Content-Type: application/x-www-form-urlencoded
    Host: accounts.google.com
    b'Accept': */*
    b'Accept-Encoding': gzip, deflate, compress
    b'Content-Type': application/x-www-form-urlencoded; charset=utf-8
    b'User-Agent': HTTPie/0.6.0
    
    refresh_token=1%2FnJZGF7hIySVtVCl8I-Y3KfXAPk84gD0X6ym7hQS8gcc&client_id=XXXX&client_secret=XXXX&grant_type=refresh_token
    
    HTTP/1.1 200 OK
    Alternate-Protocol: 443:quic
    Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    Content-Type: application/json
    Date: Mon, 16 Sep 2013 05:20:21 GMT
    Expires: Fri, 01 Jan 1990 00:00:00 GMT
    Pragma: no-cache
    Server: GSE
    Transfer-Encoding: chunked
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    X-XSS-Protection: 1; mode=block
    
    {
      "access_token": "XXXX", 
      "expires_in": 3600, 
      "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRlNDZiMGQ4Zjg1OWRhMDNjOGM3MmY5YTM3ZWM0NTFjM2RjNTM0NmUifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE3Mzk3NDI0ODc1MDc4OTM1MDY2IiwiYXRfaGFzaCI6IkJvT0lCZVVXcmthRzRBY2NpajZkaEEiLCJhdWQiOiI2NDIzMDEzNjM0NDQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InNjb2xpbmNydTAwMUBteW1haWwubGF1c2QubmV0IiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiYXpwIjoiNjQyMzAxMzYzNDQ0LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaGQiOiJteW1haWwubGF1c2QubmV0IiwiaWF0IjoxMzc5MzA4NTIxLCJleHAiOjEzNzkzMTI0MjF9.XtEDuIaEK5qe0SIFVr2l88zu3FpPBKl3_9z0D0wMCOxE-lnC4abrL71uxvMbVHvTVNbcFRs5RPHTrwPtidfw44MoukZLwVaW1c1TYBet2yuC3bZeoe7HPBZxzdMmpqBiYZOkvru3o_S5kaGp1csKzttd_fZ9nkzXITSMHxHAtbk", 
      "token_type": "Bearer"
    }
    

    所以,我需要Content-Type: "application/x-www-form-urlencoded; charset=utf-8",而不是Content-Type: "application/x-www-form-urlencoded",这样可以解决问题。

    【讨论】:

    • 我在获取访问令牌步骤中遇到了同样的问题,这一更改修复了它。谢谢!
    【解决方案2】:

    就我而言,我正在使用基于 iOS 移动应用的身份验证,但我忘记了要获得可在服务器端使用的刷新令牌,您必须获得一个授权码在移动应用程序上,将其发送到服务器,然后服务器使用该授权代码从对 Google 的 REST 调用中获取其刷新令牌(请参阅https://developers.google.com/identity/sign-in/ios/offline-access?hl=en)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      • 2013-07-21
      • 2020-06-18
      相关资源
      最近更新 更多