Page MenuHomePhabricator

Updating grants (via Special:OAuthManageMyGrants) of OAuth accepted consumers overrides its grants with empty array
Closed, ResolvedPublicBUG REPORT

Description

While debugging T409901: TypeError: array_keys(): Argument #1 ($array) must be of type array, null given by $resourceServer->getScopes(), we uncovered an interesting bug in the "update" feature of Special:OAuthManageMyGrants. This special page is not recommended for use by application developers, but no programmatic restrictions are enforced. So, if a developer doing local testing somehow finds their way to the aforementioned special page and tries to update their application grants (manually), it results in overriding their grants in the DB with an empty array ([]).

This has been tested for cases where the application is an OAuth2 client, and the grant type is either authonlyprivate or authonly. More testing is needed for consumers with requested permissions, etc.

Steps to replicate the issue (include links if applicable):

  • Visit: <local-wiki-URL>/wiki/Special:OAuthManageMyGrants/update/<oaac_id>
    • The ooac_id can be gotten quickly by trying to revoke/de-authorize the application or from the DB
  • Click "Update grants" on the form presented
  • Check the DB for the specific accepted consumer and notice that grants is now an empty array ([])

What happens?:
The oauth_accepted_consumer.oaac_grants field becomes an empty array ([]).

What should have happened instead?:
It (oauth_accepted_consumer.oaac_grants) should be whatever oauth_registered_consumer.oarc_grants is at the very least, since the user merely just clicked update without changing any data in the form.

Software version (on Special:Version page; skip for WMF-hosted wikis like Wikipedia):
Affecting master (which means it has been around for a while, I suppose).

Proposed solutions

Figure out what in ConsumerAcceptanceSubmitControl alters the grants on update, and at the very least, reuse the grants from oauth_registered_consumer.

But a better approach may be to avoid copying the grants from one table to another, since if they ever change, we'll need to keep the two copies in sync. Maybe we should review oauth_accepted_consumer and oauth_registered_consumer tables, and normalize so that the grants are in a central place of truth?

We already have ooac_user_id and ooac_consumer_id in oauth_accepted_consumer, so we can use those to query oauth_registered_consumer to get the grants, and related updates (like changes to grants, etc.) go to the consumer registrations table instead. Other ideas are welcome!

Notes
  1. Notice how the user of an example consumer app updated their grants: https://logstash.wikimedia.org/goto/df637852f48cfdeb8124430993a0a513 (timestamp: 15:56:...)
  2. Then notice how shortly after that, the app started logging warnings in Logstash: https://logstash.wikimedia.org/goto/07091fc5ab16e563a453adfaed239651 (timestamp: 15:58:...)

Event Timeline

Change #1224103 had a related patch set uploaded (by D3r1ck01; author: Derick Alangi):

[mediawiki/extensions/OAuth@master] Control: Handle accepted consumers with "auth-only" grants

https://gerrit.wikimedia.org/r/1224103

More things I noticed:

  • "normal" applications (i.e., consumer applications that are not auth-only) have the "update" link to manage grants for the application, while auth-only apps don't have the link.
normal appauth-only app
Screenshot 2026-01-07 at 6.52.19 PM.png (452×1 px, 59 KB)
Screenshot 2026-01-07 at 6.52.12 PM.png (442×1 px, 95 KB)
  • For "auth-only" consumers, one can force access manage grant page (by peeking at the consumer accepted ID via the "revoke access" link). I spoke with @Tgr, and this is not recommended. We need to find a way to enforce it programmatically because there is really nothing to update there.

Change #1224103 merged by jenkins-bot:

[mediawiki/extensions/OAuth@master] Control: Handle accepted consumers with "auth-only" grants

https://gerrit.wikimedia.org/r/1224103

Per P87456, we now have a list of affected consumers. All except 1 is non-authonly and would likely need more figuring out to understand why this happened.

A viable plan would be to run an SQL query (see the paste above) to update the grants field for affected accepted consumers, but we'll have to wait a bit for this to roll out before we run the query (so the issue doesn't get reintroduced before the fix hits all wikis in production).

The queries in P87456 look right to me, I agree that we should run the update in production.

All except 1 is non-authonly and would likely need more figuring out to understand why this happened.

I spent a bit looking into this, and I found that for OAuth 2 consumers, you can pass the 'scope' parameter to the /oauth2/authorize endpoint (https://www.mediawiki.org/wiki/Extension:OAuth#OAuth_2.0_REST_endpoints), which has the same effect as using Special:OAuthManageMyGrants, and which suffers from the same bug with irrevocable grants.

(If 'scope' is set to an empty string, it falls back to the default list of grants – to trigger the bug, it has to be set to a valid grant name, but one that is not registered for the application)

Change #1226866 had a related patch set uploaded (by Bartosz Dziewoński; author: Bartosz Dziewoński):

[mediawiki/extensions/OAuth@master] Control: Keep irrevocable grants when accepting new OAuth 2 consumers

https://gerrit.wikimedia.org/r/1226866

Change #1226866 merged by jenkins-bot:

[mediawiki/extensions/OAuth@master] Control: Keep irrevocable grants when accepting new OAuth 2 consumers

https://gerrit.wikimedia.org/r/1226866

Change #1227280 had a related patch set uploaded (by D3r1ck01; author: Derick Alangi):

[mediawiki/extensions/OAuth@wmf/1.46.0-wmf.10] Control: Handle accepted consumers with "auth-only" grants

https://gerrit.wikimedia.org/r/1227280

Change #1227282 had a related patch set uploaded (by D3r1ck01; author: Bartosz Dziewoński):

[mediawiki/extensions/OAuth@wmf/1.46.0-wmf.11] Control: Keep irrevocable grants when accepting new OAuth 2 consumers

https://gerrit.wikimedia.org/r/1227282

Change #1227280 abandoned by D3r1ck01:

[mediawiki/extensions/OAuth@wmf/1.46.0-wmf.10] Control: Handle accepted consumers with "auth-only" grants

Reason:

This is not going to be needed actually. But the others would need to be backported to wmf.11 then deployed in the late window.

https://gerrit.wikimedia.org/r/1227280

Change #1227282 merged by jenkins-bot:

[mediawiki/extensions/OAuth@wmf/1.46.0-wmf.11] Control: Keep irrevocable grants when accepting new OAuth 2 consumers

https://gerrit.wikimedia.org/r/1227282

Mentioned in SAL (#wikimedia-operations) [2026-01-15T21:06:39Z] <derick@deploy2002> Started scap sync-world: Backport for [[gerrit:1227281|Control: When saving grants, ensure array has no gaps]], [[gerrit:1227282|Control: Keep irrevocable grants when accepting new OAuth 2 consumers (T413947)]]

Mentioned in SAL (#wikimedia-operations) [2026-01-15T21:08:36Z] <derick@deploy2002> derick, d3r1ck01: Backport for [[gerrit:1227281|Control: When saving grants, ensure array has no gaps]], [[gerrit:1227282|Control: Keep irrevocable grants when accepting new OAuth 2 consumers (T413947)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2026-01-15T21:16:20Z] <derick@deploy2002> Finished scap sync-world: Backport for [[gerrit:1227281|Control: When saving grants, ensure array has no gaps]], [[gerrit:1227282|Control: Keep irrevocable grants when accepting new OAuth 2 consumers (T413947)]] (duration: 09m 41s)

Deployed the patches just a few minutes ago, and everything is already looking good. All issues have been addressed.

I'll go ahead now and apply the SQL query (P87456) to update all affected consumers with the correct grants.

Deployed the patches just a few minutes ago, and everything is already looking good. All issues have been addressed.

I'll go ahead now and apply the SQL query (P87456) to update all affected consumers with the correct grants.

Done with this and posted my comments here: P87456#352406. This is now resolved! Thanks for the collaboration @matmarex