Repository navigation
Added OIDC data:read and data:write scopes - #555
Merged
Merged
Conversation
daniel-slaugh
approved these changes
Oct 6, 2026
daniel-slaugh
left a comment
Contributor
There was a problem hiding this comment.
Two issues were flagged by the review agents. Both security issues that should be resolved, but you have a few open PRs and you mentioned you'll merge these and the changes from the v1.12 release into one branch, so I'm approving this PR in case you want to merge all these branches and resolve security issues while we test the v2.0 release candidate.:
OIDC write scope can mint permanent API keys and administer accounts
- service_account.py:56, :166; collaborator.py:54, :82, :112; workspace.py:135, :154; oidc_adapter.py:20
- oidc_write_auth guards more than data. It also covers creating service accounts and regenerating their keys, managing collaborators, deleting a workspace, and transferring workspace ownership. The consent screen says only "Create, modify, and delete your HydroServer data". The service-account endpoints return the new API key in plaintext, and that key never expires.
- Scenario: A user approves a third-party app for data:write, thinking it only edits observations → the app calls POST /service-accounts with its 1-hour token → it gets back a permanent API key → the user revokes the app, but the key still works. The same token can also transfer or delete the user's workspace. Nothing on the consent screen discloses any of this.
- Fix: Before release, keep OIDC tokens off the service-account create and regenerate routes. Put collaborator, workspace delete and transfer routes behind a separate scope (e.g. account:admin) with honest consent text. At minimum, disclose these powers in the data:write consent text.
OIDC read scope returns stored upstream credentials in plaintext
- data_connection.py:26, :91; schemas/etl/data_connection.py:262
- Both data-connection GET routes accept oidc_read_auth. DataConnectionResponse returns auth_header_value, which is read straight from a plaintext TextField. Anyone who can view the workspace already gets it back through any login method. This PR also hands it to third-party apps under a "View your HydroServer data" label.
- Scenario: A workspace stores an upstream token in a data connection → a user approves a read-only dashboard app → the app lists data connections → it receives the upstream token in plaintext and can call that third-party service as the workspace.
- Fix: Stop returning auth_header_value from GET for every login method. Replace it with a hasAuthHeader: bool, and only accept the value on POST and PATCH. Track this as its own issue, because the leak predates the scope change.
Contributor
Author
|
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Split OIDC token auth into read and write scopes for each API endpoint.