Files
windmill/backend/oauth_connect.json
T
hugocasa e26a9239a6 feat: zero-setup oauth client credentials for registry providers (#9559)
* feat: zero-setup oauth client credentials for registry-declared providers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: support client-credentials-only custom oauth providers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: add coupa client credentials provider to oauth registry

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: clarify oauth resource connect auth-method selection

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: support shared instance-level oauth client credentials

Admins can designate an instance OAuth entry's credentials as client
credentials; the connect dialog then runs the exchange server-side with
them instead of asking each user for their own. Replaces the per-provider
"Support Client Credentials Flow" toggle with a grant-type selector.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: update ee-repo-ref to be9f23b2c06b8b6ee0cd3e4d9f16bcd9e90129fb

This commit updates the EE repository reference after PR #613 was merged in windmill-ee-private.

Previous ee-repo-ref: 05643cbbc8c1bebf3509c691c5811b4057d96485

New ee-repo-ref: be9f23b2c06b8b6ee0cd3e4d9f16bcd9e90129fb

Automated by sync-ee-ref workflow.

* feat: allow both grant types on an instance oauth entry

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: bring-your-own oauth credentials from the others section

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: segmented oauth grant-type selector, always show grant

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: enable client credentials for 5 more oauth providers

Verified against official docs: bitbucket, linkedin, spotify, xero and
zoho support the standard client_credentials grant with a plain
client_id + client_secret, compatible with Windmill's token exchange.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: hide create-manually link on the managed oauth connect path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: enable client credentials for salesforce and servicenow

Salesforce CC requires the org's My Domain token endpoint (login.salesforce.com
is unsupported for that grant), so add an optional cc_token_url registry field
that the connect form prefills for the client-credentials path instead of the
shared token_url. ServiceNow uses the same instance host for both grants, so it
only needs its token URL and req_body_auth surfaced at the top level.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: add instance-level client-credentials token url override

Some providers use a per-org/instance-specific token endpoint for the
client-credentials grant that differs from the authorization-code URL.
Add an optional cc_token_url on the instance OAuth entry, surfaced in
instance settings (prefilled from the registry template) when client
credentials is selected, and used for the CC exchange and refresh while
auth-code keeps its own token URL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* style: remove redundant grant-type tags from oauth auth cards

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: extract reusable RadioCard component for the oauth auth chooser

A token-based selectable card (label, description, selected, onSelect,
optional icon) replacing the inline cards in the connect dialog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: hide sign-in option on the bring-your-own oauth path

Picking a provider from "Others" means bring your own credentials, so
the auth-code "Sign in" card (which uses the instance client) no longer
shows there — it goes straight to the client-credentials form. The
two-flow chooser stays on the instance-configured path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: restrict client-credentials token url to caller-supplied creds

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: resolve client-credentials id and secret all-or-nothing

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: host-pin client-credentials token url via instance-name input

For registry providers whose CC token URL is instance-templated (Coupa,
Salesforce My Domain, ServiceNow), the connect dialog and instance settings
collect an instance name and the backend substitutes it into the fixed-host
template, validating it as a hostname label. A free-form token URL is no longer
accepted for these providers, so the exchange host cannot be redirected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: client-credentials token url always comes from the registry

Bring-your-own CC is registry-only: the token URL is resolved server-side from
the built-in registry (host-pinned via an instance name for templated providers,
the fixed registry URL otherwise) and rejected for custom resource types. The
caller-supplied token URL field is removed from the connect dialog and the API.
Adds unit tests for the resolver.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: address CC review - sandbox CC config and instance-templated providers

Resolve `_sandbox` provider keys to the parent registry entry in the instance
settings and connect-dialog helpers, so salesforce_sandbox (and future sandbox
entries) can enable client credentials. Use the effective CC token URL template
(cc_token_url or token_url) so the instance-name field works for Coupa/ServiceNow,
and hide that field when a connect_config_template already owns the instance input
(ServiceNow). Document the authorization contract on resolve_instance_cc_credentials.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: unify instance-templated oauth onto connect_config_template

Remove the separate cc_token_url and cc_instance config fields. An instance-
templated provider now declares one connect_config_template (auth_url optional
for client-credentials-only providers like Coupa); the CC flow reads its token
URL, label and strip_suffix to host-pin the exchange. Coupa and ServiceNow move
to connect_config_template; Coupa stays drawer-only (no auth_url -> excluded from
instance settings). Salesforce CC is removed for now (its auth-code/CC host split
needs the endpoint-profiles model).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: cc_scopes defaults and instance config for client credentials

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: store empty auth_url for cc-only templated oauth providers

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: address review nits - sandbox key lookup, template doc, deref specs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: default shared client-credentials connect to cc_scopes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: support bring-your-own client credentials for instance-configured providers

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: move oauth grant-type help into per-option tooltips

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: keep instance-configured oauth providers selectable from Others

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: preserve admin-configured scopes for custom client-credentials providers

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: use cc scopes on cc refresh and enforce cc grant for bring-your-own

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: require {instance} in leftmost host label for cc token url templates

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: drop token_url from unauthenticated get_connect response

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fill byo templated resource args from the entered instance

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 136f4634aca61e74ccb045372358a1e3f6b23e75

This commit updates the EE repository reference after PR #616 was merged in windmill-ee-private.

Previous ee-repo-ref: b5083e266492e908456e39401778a9cdcea46e94

New ee-repo-ref: 136f4634aca61e74ccb045372358a1e3f6b23e75

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-06-17 16:32:01 +00:00

255 lines
8.8 KiB
JSON

{
"github": {
"auth_url": "https://github.com/login/oauth/authorize",
"token_url": "https://github.com/login/oauth/access_token",
"scopes": ["workflow", "repo"]
},
"gitlab": {
"auth_url": "https://gitlab.com/oauth/authorize",
"token_url": "https://gitlab.com/oauth/token",
"scopes": ["api"]
},
"bitbucket": {
"auth_url": "https://bitbucket.org/site/oauth2/authorize",
"token_url": "https://bitbucket.org/site/oauth2/access_token",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": ["repository"]
},
"slack": {
"auth_url": "https://slack.com/oauth/authorize",
"token_url": "https://slack.com/api/oauth.access",
"scopes": ["chat:write:user", "users:read", "users:read.email"]
},
"supabase_wizard": {
"auth_url": "https://api.supabase.com/v1/oauth/authorize",
"token_url": "https://api.supabase.com/v1/oauth/token",
"scopes": ["all"]
},
"gsheets": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/spreadsheets"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gdrive": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/drive"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gmail": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/gmail.send"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gcal": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/calendar.events"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gforms": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/forms"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gcloud": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/cloud-platform"],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"gworkspace": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": [
"https://www.googleapis.com/auth/admin.directory.group",
"https://www.googleapis.com/auth/admin.directory.user",
"https://www.googleapis.com/auth/admin.directory.user.security",
"https://www.googleapis.com/auth/admin.directory.orgunit"
],
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
},
"basecamp": {
"auth_url": "https://launchpad.37signals.com/authorization/new",
"token_url": "https://launchpad.37signals.com/authorization/token",
"scopes": [],
"extra_params": {
"type": "web_server"
}
},
"linkedin": {
"auth_url": "https://www.linkedin.com/oauth/v2/authorization",
"token_url": "https://www.linkedin.com/oauth/v2/accessToken",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": ["w_member_social", "r_liteprofile", "r_emailaddress"],
"req_body_auth": true
},
"quickbooks": {
"auth_url": "https://appcenter.intuit.com/connect/oauth2",
"token_url": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
"scopes": ["com.intuit.quickbooks.accounting"]
},
"visma": {
"auth_url": "https://connect.visma.com/connect/authorize",
"token_url": "https://connect.visma.com/connect/token",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": [
"offline_access",
"vismanet_erp_interactive_api:create",
"vismanet_erp_interactive_api:delete",
"vismanet_erp_interactive_api:read",
"vismanet_erp_interactive_api:update"
],
"cc_scopes": [
"vismanet_erp_service_api:create",
"vismanet_erp_service_api:delete",
"vismanet_erp_service_api:read",
"vismanet_erp_service_api:update"
]
},
"coupa": {
"grant_types": ["client_credentials"],
"connect_config_template": {
"display_name": "Coupa",
"label": "Coupa instance",
"placeholder": "your-instance",
"token_url": "https://{instance}.coupahost.com/oauth2/token",
"strip_suffix": ".coupahost.com"
}
},
"sage_intacct": {
"auth_url": "https://api.intacct.com/ia/api/v1/oauth2/authorize",
"token_url": "https://api.intacct.com/ia/api/v1/oauth2/token",
"scopes": ["offline_access"]
},
"spotify": {
"auth_url": "https://accounts.spotify.com/authorize",
"token_url": "https://accounts.spotify.com/api/token",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": [
"user-read-playback-state",
"user-modify-playback-state",
"user-read-currently-playing",
"playlist-read-private",
"playlist-read-collaborative",
"playlist-modify-private",
"playlist-modify-public",
"user-follow-read",
"user-read-playback-position",
"user-read-recently-played",
"user-top-read",
"user-library-modify",
"user-library-read"
]
},
"xero": {
"auth_url": "https://login.xero.com/identity/connect/authorize",
"token_url": "https://identity.xero.com/connect/token",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": ["offline_access", "accounting.transactions"],
"cc_scopes": ["accounting.transactions"]
},
"zoho": {
"auth_url": "https://accounts.zoho.com/oauth/v2/auth",
"token_url": "https://accounts.zoho.com/oauth/v2/token",
"grant_types": ["authorization_code", "client_credentials"],
"scopes": ["ZohoAssist.sessionapi.ALL"],
"cc_scopes": ["ZohoAssist.sessionapi.ALL"],
"extra_params": {
"access_type": "offline"
}
},
"snowflake_oauth": {
"connect_config_template": {
"display_name": "Snowflake",
"label": "Snowflake Account Identifier",
"placeholder": "<orgname>-<account_name>",
"help_url": "https://docs.snowflake.com/en/user-guide/admin-account-identifier#using-an-account-name-as-an-identifier",
"auth_url": "https://{instance}.snowflakecomputing.com/oauth/authorize",
"token_url": "https://{instance}.snowflakecomputing.com/oauth/token-request",
"req_body_auth": false,
"extra_params_key": "account_identifier",
"resource_mapping": { "account_identifier": "{instance}" }
}
},
"apify": {
"auth_url": "https://console.apify.com/authorize/oauth",
"token_url": "https://console-backend.apify.com/oauth/apps/token",
"scopes": ["profile", "full_api_access"],
"extra_params": {}
},
"docusign": {
"auth_url": "https://account.docusign.com/oauth/auth",
"token_url": "https://account.docusign.com/oauth/token",
"scopes": ["signature"],
"sandbox": {
"auth_url": "https://account-d.docusign.com/oauth/auth",
"token_url": "https://account-d.docusign.com/oauth/token"
}
},
"salesforce": {
"auth_url": "https://login.salesforce.com/services/oauth2/authorize",
"token_url": "https://login.salesforce.com/services/oauth2/token",
"scopes": ["api", "refresh_token", "offline_access"],
"sandbox": {
"auth_url": "https://test.salesforce.com/services/oauth2/authorize",
"token_url": "https://test.salesforce.com/services/oauth2/token"
}
},
"servicenow": {
"grant_types": ["authorization_code", "client_credentials"],
"req_body_auth": true,
"connect_config_template": {
"display_name": "ServiceNow",
"label": "ServiceNow Instance",
"placeholder": "<instance> (e.g. dev12345)",
"help_url": "https://www.servicenow.com/docs/bundle/zurich-platform-security/page/administer/security/concept/c_OAuthApplications.html",
"auth_url": "https://{instance}.service-now.com/oauth_auth.do",
"token_url": "https://{instance}.service-now.com/oauth_token.do",
"req_body_auth": true,
"strip_suffix": ".service-now.com",
"resource_mapping": {
"instance_url": "https://{instance}.service-now.com"
}
}
},
"outreach": {
"auth_url": "https://api.outreach.io/oauth/authorize",
"token_url": "https://api.outreach.io/oauth/token",
"scopes": [
"accounts.all",
"prospects.all",
"sequences.all",
"sequenceStates.all",
"tasks.all",
"mailings.read",
"mailboxes.read"
],
"req_body_auth": true
}
}