Skip to content

Je/add scopes to connect sdk #17452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/bitget/bitget.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/explorium/explorium.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/hana/hana.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/indiefunnels/indiefunnels.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/joggai/joggai.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/mumble/mumble.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/sign_plus/sign_plus.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
2 changes: 1 addition & 1 deletion components/webscrape_ai/webscrape_ai.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default {
console.log(Object.keys(this.$auth));
},
},
};
};
6 changes: 6 additions & 0 deletions packages/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

# Changelog

## [1.7.0] - 2025-07-03

### Added

- Added optional scope parameter to backendClient creation.

## [1.6.11] - 2025-07-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@pipedream/sdk",
"type": "module",
"version": "1.6.11",
"version": "1.7.0",
"description": "Pipedream SDK",
"main": "./dist/server.js",
"module": "./dist/server.js",
Expand Down
91 changes: 70 additions & 21 deletions packages/sdk/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
* https://pipedream.com/docs/workflows/domains
*/
workflowDomain?: string;

/**
* OAuth scope to request when obtaining access tokens
*/
scope?: string[];
};

/**
Expand Down Expand Up @@ -197,6 +202,7 @@
};
protected override projectId: string = "";
private staticAccessToken?: string;
private scope?: string[];

/**
* Constructs a new ServerClient instance.
Expand All @@ -209,6 +215,7 @@

this.ensureValidEnvironment(opts.environment);
this.projectId = opts.projectId;
this.scope = opts.scope;
if ("accessToken" in opts.credentials) {
this.staticAccessToken = opts.credentials.accessToken;
} else {
Expand Down Expand Up @@ -264,6 +271,16 @@
return this.ensureValidOauthAccessToken();
}

/**
* Returns true if the client is configured to use a static access token.
*
* @returns True if the client is configured to use a static access token.
*
*/
public isStaticAccessToken(): boolean {
return !!this.staticAccessToken;
}

protected authHeaders(): string | Promise<string> {
if (this.staticAccessToken) {
return `Bearer ${this.staticAccessToken}`;
Expand All @@ -281,31 +298,63 @@
as,
} = this.oauthClient

let attempts = 0;
const maxAttempts = 2;

while (!this.oauthAccessToken || this.oauthAccessToken.expiresAt - Date.now() < 1000) {
if (attempts > maxAttempts) {
throw new Error("ran out of attempts trying to retrieve oauth access token");
}
if (attempts > 0) {
// Wait for a short duration before retrying to avoid rapid retries
await new Promise((resolve) => setTimeout(resolve, 100));
for (let attempts = 0; attempts <= maxAttempts; attempts++) {
Comment on lines 301 to +304
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Clarify the retry attempt count.

The variable is named maxAttempts = 2 but the loop condition attempts <= maxAttempts means it will actually attempt 3 times (0, 1, 2). This is confusing.

Either rename the variable or adjust the loop condition:

-    const maxAttempts = 2;
+    const maxAttempts = 3; // Total attempts including the initial one

Or:

-      for (let attempts = 0; attempts <= maxAttempts; attempts++) {
+      for (let attempts = 0; attempts < maxAttempts; attempts++) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const maxAttempts = 2;
while (!this.oauthAccessToken || this.oauthAccessToken.expiresAt - Date.now() < 1000) {
if (attempts > maxAttempts) {
throw new Error("ran out of attempts trying to retrieve oauth access token");
}
if (attempts > 0) {
// Wait for a short duration before retrying to avoid rapid retries
await new Promise((resolve) => setTimeout(resolve, 100));
for (let attempts = 0; attempts <= maxAttempts; attempts++) {
const maxAttempts = 2;
while (!this.oauthAccessToken || this.oauthAccessToken.expiresAt - Date.now() < 1000) {
for (let attempts = 0; attempts < maxAttempts; attempts++) {
🤖 Prompt for AI Agents
In packages/sdk/src/server/index.ts around lines 301 to 304, the retry loop uses
maxAttempts = 2 but the loop condition attempts <= maxAttempts causes three
attempts (0, 1, 2), which is confusing. To fix this, either rename maxAttempts
to maxAttemptIndex or change the loop condition to attempts < maxAttempts so the
number of attempts matches the variable name and intent.

if (attempts > 0) {
// Wait for a short duration before retrying to avoid rapid retries
await new Promise((resolve) => setTimeout(resolve, 100));
}

const parameters = new URLSearchParams();
if (this.scope && this.scope.length > 0) {
parameters.set("scope", this.scope.join(" "));
}
parameters.set("project_id", this.projectId);
parameters.set("environment", this.environment);
try {
const response = await oauth.clientCredentialsGrantRequest(as, client, clientAuth, parameters);
const oauthTokenResponse = await oauth.processClientCredentialsResponse(as, client, response);
this.oauthAccessToken = {
token: oauthTokenResponse.access_token,
expiresAt: Date.now() + (oauthTokenResponse.expires_in || 0) * 1000,
};
break; // Successfully got token, exit retry loop
} catch (e) {
// Extract error details from OAuth response
let errorMessage = "OAuth token request failed";
let wwwAuthenticate: string | undefined;
let statusCode: number | undefined;
if (e instanceof Error) {
errorMessage = e.message;
}
// Check if the error contains response information
if (e && typeof e === "object" && "response" in e) {
const errorResponse = (e as any).response;

Check failure on line 334 in packages/sdk/src/server/index.ts

View workflow job for this annotation

GitHub Actions / Lint Code Base

Unexpected any. Specify a different type
if (errorResponse) {
statusCode = errorResponse.status;
wwwAuthenticate = errorResponse.headers?.get?.("www-authenticate") ||
errorResponse.headers?.["www-authenticate"];
// Create more specific error message based on status code
if (statusCode === 401) {
errorMessage = `OAuth authentication failed (401 Unauthorized)${wwwAuthenticate ? `: ${wwwAuthenticate}` : ""}`;

Check failure on line 341 in packages/sdk/src/server/index.ts

View workflow job for this annotation

GitHub Actions / Lint Code Base

Expected newline between consequent and alternate of ternary expression

Check failure on line 341 in packages/sdk/src/server/index.ts

View workflow job for this annotation

GitHub Actions / Lint Code Base

Expected newline between test and consequent of ternary expression
} else if (statusCode === 400) {
errorMessage = "OAuth request invalid (400 Bad Request) - check client credentials";
} else if (statusCode) {
errorMessage = `OAuth request failed with status ${statusCode}`;
}
}
}
const error = new Error(errorMessage);
(error as any).statusCode = statusCode;

Check failure on line 350 in packages/sdk/src/server/index.ts

View workflow job for this annotation

GitHub Actions / Lint Code Base

Unexpected any. Specify a different type
(error as any).wwwAuthenticate = wwwAuthenticate;

Check failure on line 351 in packages/sdk/src/server/index.ts

View workflow job for this annotation

GitHub Actions / Lint Code Base

Unexpected any. Specify a different type
// If this is the last attempt, throw the error
if (attempts >= maxAttempts) {
throw error;
}
}
}

const parameters = new URLSearchParams();
try {
const response = await oauth.clientCredentialsGrantRequest(as, client, clientAuth, parameters);
const oauthTokenResponse = await oauth.processClientCredentialsResponse(as, client, response);
this.oauthAccessToken = {
token: oauthTokenResponse.access_token,
expiresAt: Date.now() + (oauthTokenResponse.expires_in || 0) * 1000,
};
} catch {
// pass
}

attempts++;
}

return this.oauthAccessToken.token;
Expand Down
8 changes: 8 additions & 0 deletions packages/sdk/src/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,14 @@ export type ErrorResponse = {
* The error message returned by the API.
*/
error: string;
/**
* The www-authenticate header value, if present in the error response.
*/
wwwAuthenticate?: string;
/**
* Additional error headers that may be relevant for error handling.
*/
headers?: Record<string, string>;
};

/**
Expand Down
3 changes: 1 addition & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading