I am using a server-side flow validation for an app that connects to Google Drive.
I am able to retrieve the access code and exchange for an access_token and user info. I then persist the refresh_token. So, I can confirm that the client_id and client_secret are correct, but when I use the refresh_token to get a new access_token, I get a 400 response. Here's the details, I log the response from the initial token request and can confirm that the refresh_token stored to the database matches the one in the response from Google.
But when I try to use the refresh_token (programmatically and with httpie), I get the response below. Why?
% 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"
}
And here is the log output from my web application for this particular user when he logs in for the first time and I persist the 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
If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens. Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid.
Get an OAuth2 Refresh Token and Configure Your Client Because OAuth2 access expires after a limited time, an OAuth2 refresh tokenis used to automatically renew OAuth2 access.
Hey, sorry for taking so long. DiscordHTTPError: 400 Bad Request on POST /api/v7/oauth2/token { error: 'invalid_request', error_description: 'Invalid "code" in request.' } You are probably getting the authorization code wrong or the library/middlewares you are using are changing the string and making it invalid.
To begin, obtain OAuth 2.0 client credentials from the Google API Console. Then your client application requests an access token from the Google Authorization Server, extracts a token from the response, and sends the token to the Google API that you want to access.
Okay, I figured it out. This is what the Google OAauth website says the post request needs to look like:
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
If I change my httpie to use the --form switch instead of adding a ContentType header, then I do get an access token back:
% 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"
}
So, I need to have Content-Type: "application/x-www-form-urlencoded; charset=utf-8"
, instead of Content-Type: "application/x-www-form-urlencoded"
and that fixes the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With