Repository navigation
[WPB-28193] Disentangle oauth scopes (write access should not imply read access). - #5542
Conversation
5d10243 to
aa33c72
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved backward-compatibility issues affect legacy scope parsing, refresh-token permissions, empty scopes, and directive validation.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
This PR introduces independent OAuth read, write-only, and delete-only scopes while retaining legacy configuration support.
Changes:
- Adds
oauth_scopessupport across nginx, libzauth, OAuth APIs, and charts. - Updates persistence, route documentation, tests, and deployment configurations.
- Documents migration from the deprecated
oauth_scopedirective.
| File | Summary |
|---|---|
services/nginz/third_party/nginx-zauth-module/zauth_module.c |
Adds nginx scope-list handling. |
services/nginz/integration-test/conf/nginz/nginx.conf |
Tests new scope configuration. |
services/brig/test/integration/API/OAuth.hs |
Updates OAuth integration tests. |
services/brig/src/Brig/API/OAuth.hs |
Persists typed scope sets. |
libs/wire-api/test/unit/Test/Wire/API/Routes/OAuthScopes.hs |
Validates route scope declarations. |
libs/wire-api/test/unit/Test/Wire/API/OAuth.hs |
Tests scope parsing and migration. |
libs/wire-api/src/Wire/API/Routes/Public/Galley/Meetings.hs |
Updates meeting route scopes. |
libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs |
Updates conversation route scopes. |
libs/wire-api/src/Wire/API/Routes/Public.hs |
Updates scope documentation rendering. |
libs/wire-api/src/Wire/API/OAuth.hs |
Defines scopes and legacy conversion. |
libs/libzauth/libzauth/src/oauth.rs |
Implements tier-aware verification. |
libs/libzauth/libzauth/src/lib.rs |
Exports verification support. |
libs/libzauth/libzauth-c/src/zauth.h |
Declares the C API. |
libs/libzauth/libzauth-c/src/lib.rs |
Exposes the C wrapper. |
libs/cassandra-util/src/Cassandra/CQL.hs |
Exports Cassandra set support. |
libs/cassandra-util/src/Cassandra.hs |
Re-exports Cassandra support. |
integration/test/Testlib/HTTP.hs |
Adds Host-aware request support. |
integration/test/Test/OAuth.hs |
Adds OAuth integration coverage. |
integration/test/API/Nginz.hs |
Adds nginx OAuth helpers. |
docs/src/developer/reference/config-options.md |
Documents scope configuration. |
deploy/dockerephemeral/federation-v2/nginz/conf/nginx.conf |
Migrates nginx configuration. |
deploy/dockerephemeral/federation-v1/nginz/conf/nginx.conf |
Migrates nginx configuration. |
deploy/dockerephemeral/federation-v0/nginz/conf/nginx.conf |
Migrates nginx configuration. |
charts/nginz/values.yaml |
Defines new route scopes. |
charts/nginz/templates/conf/_nginx.conf.tpl |
Renders new scope directives. |
changelog.d/1-api-changes/WPB-28193-disentangle-oauth-scopes-_write-access-should-not-imply-read-access_ |
Adds API changelog entry. |
changelog.d/0-release-notes/WPB-28193-nginx-conf-syntax-changed |
Documents configuration migration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
battermann
left a comment
There was a problem hiding this comment.
Can you verify if the docs: https://docs.wire.com/latest/developer/reference/oauth.html are still up to date with this?
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical OAuth compatibility regressions and a test compilation error remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 6
Open (6)
OAuth DELETE scope compatibility is broken · New OAuth DELETE requests reject existing admin tokens · New Read/write scopes omit required DELETE authorization · New Read/write scopes omit required DELETE authorization · New T.splitOnce does not compile · New Integration DELETE route lacks compatible scope · New
Resolved since last review (1)
3a83dbe to
6f238cc
Compare
https://github.com/wireapp/wire-docs/pull/131/changes it's on my list... |
6f238cc to
848afbd
Compare
Restore the ReadConversationsCode constructor dropped by the WIP commit and give DELETE /conversations/<id>/code its own delete-only:conversations_code scope, so legacy admin:conversations_code tokens keep working. Document the scope in the route annotation and all nginz route tables.
Enforce write-only:meetings on update-meeting and delete-only:meetings on delete-meeting, document both in nginz route tables, and make old admin:meetings tokens expand to write+delete so they keep deleting meetings. Also translate the deprecated write:feature_configs tier to read for old tokens.
848afbd to
39fb4af
Compare
Fix the refresh-meeting-link route annotation that came in from develop
('WriteMeetings -> 'WriteOnlyMeetings) so the branch compiles; record the
meetings scopes in the nginz integration conf for parity with values.yaml;
update the integration test that expected delete-only:conversations_code to
be unparseable; drop the dead allScopes helper, a duplicated test assertion,
a stale scratch block, and a stale haddock example.
| - path: /meetings/([^/]*)/([^/]*)$ | ||
| envs: | ||
| - all | ||
| oauth_scopes: ["write-only:meetings", "delete-only:meetings"] |


https://wearezeta.atlassian.net/browse/WPB-28193
The problem
We need to express the following oauth access policy: we want to grant oauth access to
{PUT,DELETE} /meetings/<domain>/<id>, but not toGETon the same route.The current implementation of oauth scopes is cumulative:
write:conversationsimpliesread:conversations,admin:blaimplieswrite:bla,read:bla. This language cannot express the above policy.Here is what works: we want to grant
write:conversations, so we issuewrite:conversationstokens and addoauth_scope: conversationto the nginz route, and onPUT,POSTrequests, thewrite:is attached to it before checking against the token. We don't want to grantread:conversations, though, but that's ok, because there is no routeGET /conversations, and nginz will never construct one.Now we want to grant
write-onlyanddelete-onlyto/meetings/<id>, which does have aGETroute, so this trick does not work any more.Existing oauth apps and tokens must keep working without interruption.
The solution
Deprecate the
oauth_scopenginx directive and introduce a newoauth_scopesdirective that supports tiersread,write-only,delete-onlyinstead ofread,write,admin.Checklist
changelog.d