@uppy/companion: configurable OAuth scope and customParams via providerOptions#6277
Open
rdinita wants to merge 1 commit into
Open
@uppy/companion: configurable OAuth scope and customParams via providerOptions#6277rdinita wants to merge 1 commit into
rdinita wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 60e029f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…erOptions
OAuth scopes were hardcoded in grant.js for every provider — operators
with stricter consent-screen requirements (e.g. Microsoft tenants that
reject 'Files.Read.All' on procurement grounds, or compliance-driven
narrowing of Drive scope) had to fork or patch node_modules.
This adds two optional fields on each per-provider entry of providerOptions:
- scope: string[] — replaces the default OAuth scope.
Applied AFTER getExtraGrantConfig()
so it also overrides scopes set by
provider classes (e.g. Instagram).
- customParams: Record<string, string> — shallow-merged onto the
provider's default custom_params
(e.g. Google's access_type:'offline'
is preserved unless overridden).
Defaults are unchanged. Operators are responsible for verifying that any
narrowed scope still satisfies the listing/download paths their
integration uses (e.g. Drive's picker requires drive.readonly; narrowing
to drive.file returns an empty listing — see transloadit#4793 for the prior
maintainer discussion of this trade-off, which framed configurability
as the right path).
Tests:
- 4 new tests in provider-manager.test.js covering scope replacement,
getExtraGrantConfig override (Instagram), customParams merge with
defaults preserved (googledrive), and validation of non-array /
non-object inputs.
- All 119 existing companion tests pass with the change in place.
567d190 to
60e029f
Compare
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.
Fixes a recurring need where operators want to narrow OAuth scope per provider without forking or patching
node_modules.Problem
OAuth scopes are hardcoded in
src/config/grant.js.providerOptionsonly carrieskey/secret/credentialsURL, so there is no API to override the scope. Concrete cases:Files.Read.All(the consent prompt covers shared + SharePoint files which auditors flag) and only needs/me/drive(Files.Read).prompt: 'select_account'for multi-account UX without losing the existingaccess_type: 'offline'handshake.login_hintper tenant.Conceptually adjacent to #4793 (closed). The maintainer outcome there was to keep
drive.readonlyas the default but signal that operator-side configurability is the right path. This PR provides that path uniformly across providers, with no default changes.Solution
Two optional fields on each per-provider entry of
providerOptions:scope: string[]replaces the OAuth scope.customParams: Record<string, string>is shallow-merged onto the provider's defaultcustom_params.Both are validated (
Array.isArrayfor scope; non-null, non-array object for customParams) so misconfiguration cannot crash companion.The merge is placed after
Object.assign(grantConfig[oauthProvider], provider.getExtraGrantConfig()), so user-supplied values beat provider-class defaults (covered by a new test that overrides Instagram's hardcoded scope).scopeandcustom_paramsare not in companion's per-requestdynamiclist, so the static merge is not shadowed.When neither field is supplied, the new code paths are no-ops. Defaults match upstream.
Tests
4 new tests in
provider-manager.test.jscover:getExtraGrantConfigoverride (instagram)customParamsmerge with defaults preserved (googledrive)All 119 existing companion tests pass with the change in place. Verified with
yarn workspace @uppy/companion test --runandyarn workspace @uppy/companion typecheck.Notes
While running
yarn testlocally I hit a flaky failure in@uppy/dashboard'sGlobalSearch.browser.test.ts > Search deep folder -> open it -> click ancestor breadcrumb(timed out findinggetByRole('button', { name: 'second' })); same test passed on a rerun without code change. Independent of@uppy/companion. Happy to file a separate issue if useful.README and a
.changeset/entry (minor, additive) included.