Skip to content

Custom OAuth 2.0

The Custom OAuth 2.0 option lets you connect any service that supports the standard Authorization Code grant flow. You supply the Authorization URL, Token URL, Client ID, Client Secret, and scopes — JsWorkflows handles the redirect, token exchange, and storage.

  • Standard OAuth 2.0 Authorization Code flow
  • Token exchange via application/x-www-form-urlencoded POST to your Token URL
  • Token storage encrypted at rest in a Cloudflare Durable Object
  • Automatic token refresh at expiry — only if the provider returns a refresh_token and expires_in in the token response
  • PKCE (code challenge/verifier)
  • Token endpoints that require JSON body instead of form-encoded body
  • Non-standard grant types (client credentials, device code, etc.)
  • Providers that do not follow the standard access_token response field name
  • Scopes that require a redirect parameter other than https://oauth.jsworkflows.com/oauth2/callback

In the provider’s developer console, create an OAuth 2.0 application. Note:

  • Grant type must be Authorization Code
  • Add https://oauth.jsworkflows.com/oauth2/callback as an authorised redirect URI (exact match required)
  • Copy the Client ID, Client Secret, Authorization URL, and Token URL

Go to Settings → OAuth Connections and click Connect to Service. Select Custom (OAuth 2.0) from the service list.

Fill in the fields:

FieldDescription
OAuth Redirect URLPre-filled — copy and add to your provider’s redirect URI list
Client IDFrom your OAuth app
Client SecretFrom your OAuth app
Authorization URLThe provider’s OAuth authorization endpoint
Token URLThe provider’s token exchange endpoint
OAuth NameA friendly label visible only to you
HandleThe unique identifier used in api.getOAuthToken('your-handle') — cannot be changed after creation
ScopesSpace-separated scopes to request (e.g. read:data write:data)

Click Generate and Authorize. A popup window opens the provider’s authorization page. After you grant access, the popup closes and the connection appears in your list.

class Workflow {
async start(data, headers, api) {
const { token, error } = await api.getOAuthToken('my-custom-handle');
if (error) {
api.log('Could not get token:', error);
return;
}
const res = await fetch('https://api.example.com/resource', {
headers: { 'Authorization': `Bearer ${token}` },
});
const json = await res.json();
api.log('Response:', JSON.stringify(json));
}
}

JsWorkflows automatically refreshes the access token when it expires, using the refresh_token returned by the provider. The refresh POST uses the same Token URL you provided during setup, with standard refresh_token grant parameters.

If the provider does not return a refresh_token in the initial token response, automatic refresh is not possible. In that case, the token will stop working after it expires and you will need to reconnect the integration manually.

When you edit a Custom OAuth connection, the Authorization URL and Token URL are pre-filled from the stored values. The Client Secret is shown as a placeholder — leave it unchanged to keep the existing secret, or enter a new one to replace it.

Re-saving triggers a new OAuth authorization popup so the provider can issue a fresh token with the updated credentials or scopes.

  • No PKCE support — providers that require PKCE (common for public clients and mobile apps) will not work.
  • No JSON token body — the token request always uses application/x-www-form-urlencoded. Providers that require a JSON body are not compatible.
  • Refresh requires refresh_token — if the provider only issues short-lived access tokens without a refresh token (e.g. some social login providers), the token will expire and need manual reconnection.
  • Standard access_token field required — the token response must contain an access_token field at the top level of the JSON response.
  • One redirect URI — the fixed redirect URI is https://oauth.jsworkflows.com/oauth2/callback. Providers that do not allow this exact URI cannot be used.