对Google OAuth 2.0使用refresh_token会返回http 400错误请求

时间:2013-09-16 04:13:00

标签: oauth google-oauth

我正在对连接到Google云端硬盘的应用进行server-side flow验证。

我能够检索访问代码并交换access_token和用户信息。然后我坚持使用refresh_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

2 个答案:

答案 0 :(得分:12)

好的,我明白了。这就是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",这样可以解决问题。

答案 1 :(得分:0)

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