Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

google oauth - Migration from OAuth1 3L to OAuth2:

I'm trying to migrate existing OAuth1.0 3L tokens to OAuth2.0 for a web app. I am following the instructions at https://developers.google.com/accounts/docs/OAuth_ref Despite all my best efforts, I keep getting this response: "Invalid authorization header."

To create the Authorization header, I use Google's Java client library 1.0, the same I use in the application to talk to google calendar. I am testing with an access token. token secret, consumer key and consumer secret that work without problem (i.e. I can use these credentials to make calls to Google Calendar, etc).

This is the code I use:

    OAuthParameters oauthParameters = new OAuthParameters();
    oauthParameters.setOAuthConsumerKey("www.mywebsite.com"); // this is the same consumer key used by my app normally, without problem. mywebsite is an example, the real name is different
    oauthParameters.setOAuthConsumerSecret("XXXXX");
    oauthParameters.setOAuthToken("YYYYY");
    oauthParameters.setOAuthTokenSecret("ZZZZZZ");

    OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
    OAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
    String requestUrl = "https://accounts.google.com/o/oauth2/token";
    String header = oauthHelper.getAuthorizationHeader(requestUrl, "POST", oauthParameters);
    String payload = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Amigration%3Aoauth1&client_id="+clientId+"&client_secret="+clientSecret;

    HttpClient httpClient = new DefaultHttpClient();

    HttpPost httpPost = new HttpPost(requestUrl);
    httpPost.addHeader("Authorization", header);
    httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
    httpPost.setEntity(new ByteArrayEntity(payload.getBytes()));
    String response = httpClient.execute(httpPost, new BasicResponseHandler());

and this is the wire trace produced by HttpClient:

>> "POST /o/oauth2/token HTTP/1.1[
][
]"
>> "Authorization: OAuth realm="", oauth_signature="ixVbjINI6pgPU2RqXGiQRbPGY%3D", oauth_nonce="486642280771700", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="www.mywebsite.com", oauth_token="YYYYY", oauth_timestamp="1395127834"[
][
]"
>> "Content-Type: application/x-www-form-urlencoded[
][
]"
>> "Content-Length: 193[
][
]"
>> "Host: accounts.google.com[
][
]"
>> "Connection: Keep-Alive[
][
]"
>> "User-Agent: Apache-HttpClient/4.3.2 (java 1.5)[
][
]"
>> "[
][
]"
>> "grant_type=urn%ietf%params%oauth%grant-type%migration%oauth1&client_id=12345&client_secret=ABCDE"
<< "HTTP/1.1 400 Bad Request[
][
]"
<< "Cache-Control: no-cache, no-store, max-age=0, must-revalidate[
][
]"
<< "Pragma: no-cache[
][
]"
<< "Expires: Fri, 01 Jan 1990 00:00:00 GMT[
][
]"
<< "Date: Tue, 18 Mar 2014 07:30:39 GMT[
][
]"
<< "Content-Type: application/json[
][
]"
<< "X-Content-Type-Options: nosniff[
][
]"
<< "X-Frame-Options: SAMEORIGIN[
][
]"
<< "X-XSS-Protection: 1; mode=block[
][
]"
<< "Server: GSE[
][
]"
<< "Alternate-Protocol: 443:quic[
][
]"
<< "Transfer-Encoding: chunked[
][
]"
<< "[
][
]"
<< "5a[
][
]"
<< "{[
]"
<< "  "error" : "invalid_request",[
]"
<< "  "error_description" : "Invalid authorization header."[
]"
<< "}"
<< "[
][
]"
<< "0[
][
]"
<< "[
][
]"

where 12345 and ABCDE are obviously placeholders for the real OAuth2 app credentials.

I have double and triple checked that all the parameters set in OAuthParameters are the same used by the normal code that is currently working using OAuth1 (even using a step-by-step debugger to verify the values at the time the signature is calculated by OAuthHmacSha1Signer.getSignature()).

I looked at the Authorization header in HTTP requests sent by the current Google Client APIs that use OAuth1 (and that work fine), and apart obviously from signature, nonce and timestamp they look identical to the one sent by this migration call.

I even tried a test migration request , which failed, then used a debugger to run the old code and inject method, URL, nonce and timestamp used by the migration call, and the signature calculated by the old code was identical, given identical params.

Any clues of why the Authorization header is still reported as invalid?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When generating the base string you will need to ensure that each individual parameter is URL encoded before constructing the base string.

As per the oAuth documentation to sign OAuth 1.0 requests the base string is made up of 3 components

  • The HTTP request method
  • The base URL the request is being sent to
  • A normalized string of the parameters in the request

When constructing the base string you need to do the following

  • Ensure HTTP request method is POST
  • URL encode the base URL
  • Ensure the three POST body parameters [client_id, client_secret, grant_type] are included in the normalized request parameters
  • Ensure each parameter is individually URL encoded and then URL encode the complete normalized request parameters string. So in effect, some of the paramters are double URL encoded. This double URL encoding is mentioned in Using OAuth with the Google Data APIs#Signing Requests for the oauth_token

Only after doing all these steps did I get the migration request to work and I received a valid refresh_token

Below is a sample base string

POST&https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken&client_id%3Dxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com%26client_secret%3Dxxxxxxxxxxxx%26grant_type%3Durn%253Aietf%253Aparams%253Aoauth%253Agrant-type%253Amigration%253Aoauth1%26oauth_consumer_key%3Dxxxxxxxxx%26oauth_nonce%3D4106001%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1400779530%26oauth_token%3D1%252FkklP1YPy_AULt7j_tttttt_tterwerkj_dfj45dflk

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...