Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetAccessToken don't work with Google OAuth1 API (the token is double encoded) #106

Open
hiteule opened this issue Dec 10, 2012 · 2 comments
Assignees
Labels

Comments

@hiteule
Copy link

hiteule commented Dec 10, 2012

Hi,

The getAccessToken don't work with the google oauth1 api.
The api return this error :
signature_invalid base_string:POST&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetAccessToken&oauth_consumer_key%3D42424242.apps.googleusercontent.com%26oauth_nonce%3Daf0b971774829b8530ab20c5b21b3f97%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1355148916%26oauth_token%3D4%252FKO4KYSdwSWvHOywPd7aY-8kWEwBl%26oauth_verifier%3DY5u4TXakuzCV7PySd62jVkzI%26oauth_version%3D1.0

The problem is located in the encoding of the token which is encoded two times.
This problem occurs on the google oauth1 api because the token contains a "/".

You can reproduce this bug with this endpoint :
https://www.google.com/accounts/OAuthGetRequestToken
https://www.google.com/accounts/OAuthAuthorizeToken
https://www.google.com/accounts/OAuthGetAccessToken

Bye

@ghost ghost assigned themattharris Feb 19, 2013
@themattharris
Copy link
Owner

Section 3.4.1.3.2 of the OAuth 1.0a specification (http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2) states that the values should be encoded and then concatenated to form the base string.

also, looking at googles GData documentation shows the same %252F component in the oauth_token (ref: https://developers.google.com/gdata/articles/oauth#Signing)

can you share the exact error Google responds with when you use tmhOAuth to make requests?

@hiteule
Copy link
Author

hiteule commented Feb 19, 2013

Hi,

The exact error of Google Api when I make the GetAccessToken request is :

signature_invalid
base_string:POST&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetAccessToken&oauth_consumer_key%3D885116161353.apps.googleusercontent.com%26oauth_nonce%3D3009d7b73288f87b253b167e811699fc%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1361267168%26oauth_token%3D4%252FfzZ-jsCiqkuMKoRuRWwKV4tUPppY%26oauth_verifier%3D7HXQDLk4Rl4EMS6VsByS2Yo8%26oauth_version%3D1.0

And the token I use to make this request is :

4/fzZ-jsCiqkuMKoRuRWwKV4tUPppY

Here you can find a sample code to reproduce this issue :

<?php
session_start();

require_once('./tmhOAuth.php');

$tmh = new tmhOAuth(array(
    'consumer_key'    => '42.apps.googleusercontent.com',
    'consumer_secret' => 'xXXX/42YyYyYzZzZz',
));

if (isset($_GET['oauth_verifier'])) {
    $tmh->config['user_token']  = $_SESSION['tmh']['oauth_token'];
    $tmh->config['user_secret'] = $_SESSION['tmh']['oauth_token_secret'];

    // Here the token value is : 4/fzZ-jsCiqkuMKoRuRWwKV4tUPppY
    echo '<pre>';var_dump($tmh->config['user_token']);echo '</pre>';

    $code = $tmh->request(
        'POST',
        'https://www.google.com/accounts/OAuthGetAccessToken',
        array('oauth_verifier' => $_GET['oauth_verifier'])
    );

    // At this point the Google API respond an error like this :
    //
    // signature_invalid base_string:POST&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetAccessToken
    // &oauth_consumer_key%3D885116161353.apps.googleusercontent.com%26oauth_nonce%3D3009d7b73288f87b253b167e811699fc%26
    // oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1361267168%26oauth_token%3D4%252FfzZ-jsCiqkuMKoRuRWwKV4tUPppY%26
    // oauth_verifier%3D7HXQDLk4Rl4EMS6VsByS2Yo8%26oauth_version%3D1.0

    echo '<pre>';var_dump($tmh->response['response']);echo '</pre>';die;
} elseif (isset($_GET['authenticate'])) {
    $code = $tmh->request(
        'POST',
        'https://www.google.com/accounts/OAuthGetRequestToken',
        array(
            'oauth_callback' => 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
            'scope'          => 'http://www.google.com/m8/feeds/',
        )
    );

    if ($code == 200) {
        $_SESSION['tmh'] = $tmh->extract_params($tmh->response['response']);
        $url = 'https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=' . $_SESSION['tmh']['oauth_token'];
        header('Location: ' . $url);
    }
}

echo '<a href="?authenticate">GO</a>';

When I patch the tmhOAuth lib to encode the token one time, the api work perfectly.
This is my quick evil patch :

--- a/trunk/include/skyobjects/external/tmhOAuth/tmhOAuth.php
+++ b/trunk/include/skyobjects/external/tmhOAuth/tmhOAuth.php
@@ -266,5 +266,5 @@
    * @return void prepared values are stored in class variables
    */
-  private function prepare_params($params) {
+  private function prepare_params($params, $encodeAccessToken = true) {
     // do not encode multipart parameters, leave them alone
     if ($this->config['multipart']) {
@@ -288,6 +288,8 @@
     // encode. Also sort the signed parameters from the POST parameters
     foreach ($this->signing_params as $k => $v) {
-      $k = $this->safe_encode($k);
-      $v = $this->safe_encode($v);
+      if ($k != 'oauth_token' || $encodeAccessToken == true) {
+        $k = $this->safe_encode($k);
+        $v = $this->safe_encode($v);
+      }
       $_signing_params[$k] = $v;
       $kv[] = "{$k}={$v}";
@@ -367,8 +369,8 @@
    * @param string $useauth whether to use authentication when making the request.
    */
-  private function sign($method, $url, $params, $useauth) {
+  private function sign($method, $url, $params, $useauth, $encodeAccessToken = true) {
     $this->prepare_method($method);
     $this->prepare_url($url);
-    $this->prepare_params($params);
+    $this->prepare_params($params, $encodeAccessToken);

     // we don't sign anything is we're not using auth
@@ -411,4 +413,14 @@
     return $this->curlit();
   }
+
+  public function requestAccessToken($method, $url, $params=array(), $useauth=true, $multipart=false) { 
+    $this->config['multipart'] = $multipart;
+    
+    $this->create_nonce();
+    $this->create_timestamp();
+    
+    $this->sign($method, $url, $params, $useauth, false);
+    return $this->curlit();
+  } 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants