Pipedream Connect lets your users authenticate third-party apps inside your product. Here is everything you need to know before you ship it.
What Pipedream Connect Is
Pipedream Connect is a component of Pipedream that handles OAuth and API key authentication on behalf of your users. Instead of building OAuth flows for every service your product integrates with, Connect provides a hosted UI where users connect their apps (Slack, Google, Salesforce, 3,000+ others), and Pipedream stores and refreshes the tokens. Your workflows use those tokens to act on behalf of the user.
It is a genuinely useful product that saves months of OAuth infrastructure work. It also has specific constraints that are not obvious until you are deep into implementation.
The Basic Architecture
// Your backend: create a Connect token for a user
// Connect is OAuth-based and project-scoped. First exchange your OAuth
// client credentials for an access token, then create a Connect token.
const PROJECT_ID = process.env.PIPEDREAM_PROJECT_ID; // e.g. "proj_abc123"
// 1. Exchange client_id/client_secret for an access token (valid ~1 hour)
const tokenResp = await fetch("https://api.pipedream.com/v1/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.PIPEDREAM_CLIENT_ID,
client_secret: process.env.PIPEDREAM_CLIENT_SECRET,
}),
});
const { access_token } = await tokenResp.json();
// 2. Create a Connect token for a user (project-scoped endpoint)
const response = await fetch(
`https://api.pipedream.com/v1/connect/${PROJECT_ID}/tokens`,
{
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
"X-PD-Environment": "production",
},
body: JSON.stringify({
external_user_id: "your-user-id-123", // your app's user ID
allowed_origins: ["https://yourapp.com"],
}),
}
);
const { token } = await response.json();
// Send this token to your frontend to initiate the Connect flow// Your frontend: initiate the Connect UI for the user
import { createFrontendClient } from "@pipedream/sdk/browser";
const pd = createFrontendClient();
async function connectSlack() {
await pd.connectAccount({
app: "slack",
token: connectToken, // token from your backend
onSuccess: ({ id: accountId }) => {
// Store this accountId in your database -- it references the connected account
saveAccountId(userId, "slack", accountId);
},
onError: (err) => {
console.error(`Connect error: ${err.message}`);
},
});
}// Your Pipedream workflow: use the connected account on behalf of the user
export default defineComponent({
props: {
slack: {
type: "app",
app: "slack",
},
},
async run({ steps, $ }) {
// The connected account is automatically used -- no manual token handling
const result = await fetch("https://slack.com/api/chat.postMessage", {
headers: { Authorization: `Bearer ${this.slack.$auth.oauth_access_token}` },
// ...
});
},
});Key Constraints to Know Before You Build
1. The authentication UI shows Pipedream branding
When users go through the Connect flow to authorise an app, they see Pipedream's UI and brand. For internal tools and developer products this is usually fine. For consumer products or enterprise SaaS with white-label requirements, you need the Enterprise plan for a white-label option, or you need to build your own OAuth proxy.
2. Users consent to Pipedream's data processing
The OAuth consent screen tells users that Pipedream will have access to process their data. For enterprise contracts with strict data processing addenda, this may require review before you can use Connect.
3. You cannot inspect or modify token storage
Tokens are stored and managed entirely by Pipedream. You cannot export them, move them to your own vault, or inspect them. If you ever leave Pipedream, you cannot migrate stored tokens -- users would need to re-authenticate in any replacement system.
4. Account management is API-first
The Connect dashboard includes a Users tab where you can view users, inspect their connected accounts, and delete individual accounts from the UI. For bulk revocation or programmatic management at scale, you use the Connect API.
Managing Accounts Programmatically
// Account management runs on your backend with an OAuth access token
// (obtain it via the client-credentials exchange shown earlier).
const PROJECT_ID = process.env.PIPEDREAM_PROJECT_ID; // e.g. "proj_abc123"
const baseHeaders = {
Authorization: `Bearer ${accessToken}`, // OAuth access token, not a raw API key
"X-PD-Environment": "production",
};
// List all connected accounts for a user (external_user_id is a query param)
async function getUserAccounts(externalUserId) {
const resp = await fetch(
`https://api.pipedream.com/v1/connect/${PROJECT_ID}/accounts?external_user_id=${externalUserId}`,
{ headers: baseHeaders }
);
return resp.json(); // { data: [ ...connected app accounts ] }
}
// Revoke a specific connected account (e.g. when user disconnects)
async function revokeAccount(accountId) {
await fetch(
`https://api.pipedream.com/v1/connect/${PROJECT_ID}/accounts/${accountId}`,
{ method: "DELETE", headers: baseHeaders }
);
}
// Revoke ALL accounts for a user (e.g. on account deletion -- GDPR)
async function deleteAllUserAccounts(externalUserId) {
const { data } = await getUserAccounts(externalUserId);
await Promise.all(data.map(acc => revokeAccount(acc.id)));
}Wire deleteAllUserAccounts into your user deletion flow before launch. GDPR and similar regulations require that connected app tokens be revoked when a user deletes their account. Missing this is a compliance gap.Handling Token Refresh Failures
OAuth tokens expire. Pipedream handles refresh automatically -- but refresh can fail if the user revokes access from the third-party app's side, or if the third-party API has an outage. Your workflows need to handle this gracefully.
export default defineComponent({
props: { slack: { type: "app", app: "slack" } },
async run({ steps, $ }) {
try {
const result = await callSlackApi(this.slack.$auth.oauth_access_token);
return result;
} catch (error) {
if (error.status === 401) {
// Token is invalid or revoked -- notify your app so the user can reconnect
await notifyUserToReconnect(steps.trigger.event.userId, "slack");
$.flow.exit("Token revoked -- user notified to reconnect");
}
throw error; // re-throw other errors
}
},
});Quick Reference
- Create a Connect token per user from your backend -- never expose your API key to the frontend
- Store the accountId returned by onSuccess in your database -- it is your reference to the connected app
- Revoke accounts on user deletion -- wire this into your GDPR/data deletion flow
- Handle 401 errors in workflows by notifying the user to reconnect
- White-label auth requires Enterprise plan -- plan for this in your pricing model if selling to enterprise
- You cannot export or migrate stored tokens -- factor this into your vendor lock-in assessment