I'm using the mwclient python library to try and make automated page edits to wikitech. The code I have works on a local test wiki, but it fails with an invalid nonce error when run against wikitech and labtestwikitech.
A reproduction boils down to this python snippet:
import mwclient consumer_token = 'your consumer token here' consumer_secret = 'your consumer secret here' access_token = 'your access token here' access_secret = 'your access secret here' site = mwclient.Site( 'labtestwikitech.wikimedia.org', consumer_token=consumer_token, consumer_secret=consumer_secret, access_token=access_token, access_secret=access_secret )
When the Site object is created it calls /w/api.php?format=json&continue=&meta=siteinfo|userinfo|userinfo&action=query&siprop=general|namespaces&uiprop=groups|rights|blockinfo|hasmsg to get some basic metadata. This initial API call dies with the consumer nonce error.
With a bit more magic you can get full debug logs for the request into Logstash (set a X-Wikimedia-Debug: log header via the backing requests python library). That told me that BagOStuff::add() was being called twice for the same nonce, but didn't help figure out quite why. I live hacked a log with an exception trace into MemcachedPeclBagOStuff::add to find the call paths:
"exception": { "class": "Exception", "message": "0.42272100 1477437607", "code": 0, "file": "/srv/mediawiki/php-1.28.0-wmf.22/includes/libs/objectcache/MemcachedPeclBagOStuff.php:174", "trace": [ "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/backend/MWOAuthDataStore.php:108", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:759", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:707", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:611", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/backend/MWOAuthServer.php:160", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/api/MWOAuthSessionProvider.php:80", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:486", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:189", "/srv/mediawiki/php-1.28.0-wmf.22/includes/WebRequest.php:735", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:128", "/srv/mediawiki/php-1.28.0-wmf.22/includes/Setup.php:759", "/srv/mediawiki/php-1.28.0-wmf.22/includes/WebStart.php:137", "/srv/mediawiki/php-1.28.0-wmf.22/api.php:38", "/srv/mediawiki/w/api.php:3" ] } },
"exception": { "class": "Exception", "message": "0.44190500 1477437607", "code": 0, "file": "/srv/mediawiki/php-1.28.0-wmf.22/includes/libs/objectcache/MemcachedPeclBagOStuff.php:174", "trace": [ "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/backend/MWOAuthDataStore.php:108", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:759", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:707", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/lib/OAuth.php:611", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/backend/MWOAuthServer.php:160", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/api/MWOAuthSessionProvider.php:80", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:486", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:189", "/srv/mediawiki/php-1.28.0-wmf.22/includes/WebRequest.php:735", "/srv/mediawiki/php-1.28.0-wmf.22/includes/user/User.php:3149", "/srv/mediawiki/php-1.28.0-wmf.22/includes/user/User.php:3448", "/srv/mediawiki/php-1.28.0-wmf.22/includes/user/LocalIdLookup.php:72", "/srv/mediawiki/php-1.28.0-wmf.22/includes/user/CentralIdLookup.php:156", "/srv/mediawiki/php-1.28.0-wmf.22/includes/user/CentralIdLookup.php:191", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/backend/MWOAuthUtils.php:279", "/srv/mediawiki/php-1.28.0-wmf.22/extensions/OAuth/api/MWOAuthSessionProvider.php:95", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:486", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:189", "/srv/mediawiki/php-1.28.0-wmf.22/includes/WebRequest.php:735", "/srv/mediawiki/php-1.28.0-wmf.22/includes/session/SessionManager.php:128", "/srv/mediawiki/php-1.28.0-wmf.22/includes/Setup.php:759", "/srv/mediawiki/php-1.28.0-wmf.22/includes/WebStart.php:137", "/srv/mediawiki/php-1.28.0-wmf.22/api.php:38", "/srv/mediawiki/w/api.php:3" ] } },
This points to MWOAuthSessionProvider::provideSessionInfo where the request is verified (first stack trace) and then MWOAuthUtils::getLocalUserFromCentralId is called to get the user object (second stack trace). During the getLocalUserFromCentralId call User::getRights is called which circles right back around to calling MWOAuthSessionProvider::provideSessionInfo a second time (and recursively).
This loop doesn't seem to happen on "normal" SUL wikis. I haven't tested for it on an other non-SUL wikis besides wikitech and labtestwikitech.