Page MenuHomePhabricator

Unable to get edit token - invalid signature in authorization header
Closed, InvalidPublic

Description

I just created an owner-only Oauth consumer with rights to test.wikipedia.org.

I'm trying to get an edit token from the API, in a SWAP notebook, and failing.

This code doesn't work:

import requests
from requests_oauthlib import OAuth1

auth1 = OAuth1(smtr_config.consumer_key, 
               smtr_config.consumer_secret, 
               smtr_config.access_key, 
               smtr_config.access_secret)

requests.get(
    url="http://test.wikipedia.org/w/api.php",
    params={
        'action': "query",
        'meta': "tokens",
        'type': "csrf",
        'format': "json"
        },
    headers={'User-Agent': "jmorgan@wikimedia.org"},
    auth=auth1,
    ).json()

It yields the following error:

{'error': {'*': 'See https://test.wikipedia.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> for notice of API deprecations and breaking changes.',
  'code': 'mwoauth-invalid-authorization',
  'info': 'The authorization headers in your request are not valid: Invalid signature'},
 'servedby': 'mw1382'}

I've use the same code for a bot account regularly, and it works fine.

Making the same API call (https://test.wikipedia.org/w/api.php?type=csrf&action=query&format=json&meta=tokens) from a browser while logged in works; I get a token.

I found this related task from 2017 (T167813) and tried to follow the guidance in it, but I have not had any success. Although running the following code shows that my client seems to have the proper grants, at least:

import jwt
import requests
from requests_oauthlib import OAuth1

auth1 = OAuth1(smtr_config.consumer_key, 
               smtr_config.consumer_secret, 
               smtr_config.access_key, 
               smtr_config.access_secret)

r=requests.get(url='https://test.wikipedia.org/w/index.php', params={'title': 'Special:OAuth/identify'}, auth=auth1)
print(jwt.decode(r.text, verify=False))

What am I missing here? Adding Gergo as a subscriber because it seems like he's triaged several similar requests in the past.

Event Timeline

The API URL should be https, not http. Presumably GET requests get redirected, but the server does not know about that and uses the final URL for calculating the signature, and so there's a mismatch.

In general, the signature is a pain point - if it fails, all we know is that the server and the client calculated a different checksum, and there is no easy way (probably no way at all) to identify which element going into the signature caused it. OAuth 2 does not involve signing, so using that might be an option. Although using OAuth 2 with accidentally-http URLs would probably be insecure...