Search code examples
phpauthenticationoauthtrello

Getting Invalid Signature when accessing tokens in Trello API OAuth


I am trying to implement a wrapper for trello api in PHP. I am getting "Invalid signature" in last step of OAuth process where I have to get access tokens from trello api. Just by this message I just can't debug what am I doing wrong.

Basically what I did was...

  1. Send a request for fetch request tokens (https://trello.com/1/OAuthGetRequestToken). This went well. I got back two parameters oauth_token and oauth_token_secret in response.
  2. Then I opened the trello authorization page url (https://trello.com/1/OAuthAuthorizeToken) with parameters oauth_token from step 1, app name and a return url at localhost. This went well too. Trello redirected to localhost/callback with parameters oauth_token and oauth_verifier.
  3. In callback, I finally sent request to fetch access tokens (https://trello.com/1/OAuthGetAccessToken). I added oauth_token & oauth_token_secret from step 1, oauth_verifier from step 2 and a signature using HMAC-SHA1 method. This went awry when I got a 500 internal error with message "Invalid signature"!!!

Does anybody have an idea what might be wrong?

Here is the code I used in callback.

$nonce = md5(mt_rand());
$timestamp = time();

$oauth_signature_base = 'GET&'.
    rawurlencode('https://trello.com/1/OAuthGetAccessToken').'&'.
    rawurlencode(implode('&', [
        'oauth_consumer_key='.rawurlencode('CONSUMER_KEY_HERE'),
        'oauth_nonce='.rawurlencode($nonce),
        'oauth_signature_method='.rawurlencode('HMAC-SHA1'),
        'oauth_timestamp='.rawurlencode($timestamp),
        'oauth_token='.rawurlencode('OAUTH_TOKEN_HERE'),
        'oauth_token_secret='.rawurlencode('OAUTH_TOKEN_SECRET_HERE'),
        'oauth_verifier='.rawurlencode('OAUTH_VERIFIER_HERE'),
        'oauth_version='.rawurlencode('1.0')
        ]));

$signature = base64_encode(hash_hmac('sha1', $oauth_signature_base, 'CONSUMER_SECRET_HERE&', true));

$params = [
    'oauth_consumer_key='.rawurlencode('CONSUMER_KEY_HERE'),
    'oauth_nonce='.rawurlencode($nonce),
    'oauth_signature_method='.rawurlencode('HMAC-SHA1'),
    'oauth_timestamp='.rawurlencode($timestamp),
    'oauth_token='.rawurlencode('OAUTH_TOKEN_HERE'),
    'oauth_token_secret='.rawurlencode('OAUTH_TOKEN_SECRET_HERE'),
    'oauth_verifier='.rawurlencode('OAUTH_VERIFIER_HERE'),
    'oauth_version='.rawurlencode('1.0'),
    'oauth_signature='.rawurlencode($signature)
];
file_get_contents(sprintf('%s?%s', 'https://trello.com/1/OAuthGetAccessToken', implode('&', $params)));

Solution

  • The oauth token secret should not be included in the URL parameters, either in generating the base string or when sending the actual request. The token secret is used only as part of the hash key. See modified code below:

    $nonce = md5(mt_rand());
    $timestamp = time();
    
    $oauth_signature_base = 'GET&'.
    rawurlencode('https://trello.com/1/OAuthGetAccessToken').'&'.
    rawurlencode(implode('&', [
        'oauth_consumer_key='.rawurlencode('CONSUMER_KEY_HERE'),
        'oauth_nonce='.rawurlencode($nonce),
        'oauth_signature_method='.rawurlencode('HMAC-SHA1'),
        'oauth_timestamp='.rawurlencode($timestamp),
        'oauth_token='.rawurlencode('OAUTH_TOKEN_HERE'),
        'oauth_verifier='.rawurlencode('OAUTH_VERIFIER_HERE'),
        'oauth_version='.rawurlencode('1.0')
        ]));
    
    //token secret should be (singly) URL encoded if not already
    $signature = base64_encode(hash_hmac('sha1', $oauth_signature_base, 'CONSUMER_SECRET_HERE&TOKEN_SECRET_HERE', true));
    
    $params = [
    'oauth_consumer_key='.rawurlencode('CONSUMER_KEY_HERE'),
    'oauth_nonce='.rawurlencode($nonce),
    'oauth_signature_method='.rawurlencode('HMAC-SHA1'),
    'oauth_timestamp='.rawurlencode($timestamp),
    'oauth_token='.rawurlencode('OAUTH_TOKEN_HERE'),
    'oauth_verifier='.rawurlencode('OAUTH_VERIFIER_HERE'),
    'oauth_version='.rawurlencode('1.0'),
    'oauth_signature='.rawurlencode($signature)
    ];
    file_get_contents(sprintf('%s?%s', 'https://trello.com/1/OAuthGetAccessToken', implode('&', $params)));