-
Notifications
You must be signed in to change notification settings - Fork 491
Feature: Netsuite oauth provider #891
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
base: dev
Are you sure you want to change the base?
Feature: Netsuite oauth provider #891
Conversation
- Implement NetSuite OAuth provider following existing patterns - Add NetSuite to standardProviders list and OAuth registry - Add netsuiteAccountId configuration field to schemas - Support NetSuite's account-specific endpoints - Include comprehensive documentation NetSuite OAuth provider supports: - OAuth 2.0 Authorization Code Grant flow - Account-specific authorization and token endpoints - User profile retrieval from NetSuite employee records - Access token validation - Configurable account ID via environment or config
|
@sicarius97 is attempting to deploy a commit to the Stack Team on Vercel. A member of the Team first needs to authorize it. |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds NetSuite OAuth support across backend, shared schemas/types, dashboard UI, branding, and templates: new NetSuiteProvider, registration and payload wiring (netsuiteAccountId), schema and CRUD additions, UI form field and icon/color assets. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Backend as Backend OAuth Controller
participant Provider as NetSuiteProvider
participant NetSuite as NetSuite OAuth2
Client->>Backend: Start OAuth (provider=netsuite)
Backend->>Provider: create({ clientId, clientSecret, accountId })
Note right of Provider `#DDEBEF`: Configure issuer, auth/token endpoints, scopes
Backend->>NetSuite: Redirect user to Authorization Endpoint
NetSuite-->>Client: Login & consent
Client->>Backend: Callback with code
Backend->>NetSuite: Token request (code)
NetSuite-->>Backend: TokenSet (access_token, expires)
Backend->>Provider: postProcessUserInfo(TokenSet)
Provider->>NetSuite: GET /userinfo (Bearer)
NetSuite-->>Provider: User info JSON (may include accountId)
Provider-->>Backend: OAuthUserInfo (accountId, email, name)
Backend-->>Client: Session established
sequenceDiagram
autonumber
participant Scheduler as Token Checker
participant Provider as NetSuiteProvider
participant NetSuite as NetSuite OAuth2
Scheduler->>Provider: checkAccessTokenValidity(accessToken)
Provider->>NetSuite: GET /services/rest/.../oauth2/v1/userinfo (Bearer)
alt 200 OK
NetSuite-->>Provider: 200 OK
Provider-->>Scheduler: true
else non-OK / error
NetSuite--x Provider: Error/Non-OK
Provider-->>Scheduler: false
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds NetSuite as a new OAuth provider to the Stack authentication system. It enables users to authenticate using their NetSuite accounts by implementing the necessary OAuth flow and configuration.
- Adds "netsuite" to the list of standard OAuth providers
- Implements NetSuite-specific OAuth provider with account ID configuration
- Adds schema validation and configuration support for NetSuite account ID parameter
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/stack-shared/src/utils/oauth.tsx | Adds "netsuite" to standardProviders array |
| packages/stack-shared/src/schema-fields.ts | Defines schema validation for NetSuite account ID |
| packages/stack-shared/src/interface/crud/projects.ts | Adds NetSuite account ID to OAuth provider schemas |
| packages/stack-shared/src/config/schema.ts | Integrates NetSuite account ID into environment configuration |
| apps/backend/src/oauth/providers/netsuite.tsx | Implements complete NetSuite OAuth provider class |
| apps/backend/src/oauth/index.tsx | Registers NetSuite provider and handles configuration |
| apps/backend/src/lib/projects.tsx | Maps NetSuite account ID in project configuration |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Summary
This PR adds NetSuite as a new OAuth provider to the Stack Auth system. The implementation follows the established patterns used by other OAuth providers in the codebase, particularly those requiring additional configuration parameters like Microsoft (tenant ID) and Facebook (config ID).
The changes span multiple layers of the application:
Core Provider Implementation: A new NetSuiteProvider class extends OAuthBaseProvider with NetSuite-specific logic. The implementation handles NetSuite's unique OAuth characteristics, including account-specific endpoints (using the account ID in URLs like https://{accountId}.app.netsuite.com/app/login/oauth2/authorize.nl) and non-standard userinfo responses that can return either single records or arrays.
Schema and Configuration: The PR adds proper schema validation through oauthNetSuiteAccountIdSchema with Yup validation and OpenAPI documentation. The account ID field is integrated at the environment configuration level alongside other provider-specific parameters, with proper typing and default values.
Integration Points: NetSuite is added to the standardProviders array, making it available throughout the application wherever OAuth providers are enumerated. The provider is registered in the OAuth provider mapping with proper parameter passing for the account ID configuration.
Data Flow: The implementation includes robust user data extraction logic that handles NetSuite's variable response formats, with fallbacks for different response structures and comprehensive error handling when user information cannot be extracted.
This addition integrates seamlessly with the existing OAuth infrastructure, requiring no changes to core OAuth logic while properly handling NetSuite's enterprise-specific requirements.
Confidence score: 4/5
- This PR is generally safe to merge with good implementation following established patterns
- Score reflects the complexity of OAuth provider integration and the need for thorough testing of NetSuite-specific logic
- Pay close attention to the user data extraction logic in
apps/backend/src/oauth/providers/netsuite.tsxwhich handles multiple response formats
7 files reviewed, 1 comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/backend/src/oauth/providers/netsuite.tsx (2)
45-52: Consider adding retry logic for userinfo endpoint.The userinfo endpoint fetch doesn't have any retry logic. NetSuite APIs can sometimes have transient failures, so consider adding retry logic similar to other OAuth providers in the codebase.
113-119: Consider adding specific error handling in checkAccessTokenValidity.The current implementation returns
falsefor any error, which could hide important issues. Consider logging errors or differentiating between network failures and authentication failures.async checkAccessTokenValidity(accessToken: string): Promise<boolean> { try { const res = await fetch(`https://${this.accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/userinfo`, { method: "GET", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, }); return res.ok; } catch (error) { + // Log the error for debugging purposes while still returning false + console.error("Failed to validate NetSuite access token:", error); return false; } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/backend/src/lib/projects.tsx(1 hunks)apps/backend/src/oauth/index.tsx(3 hunks)apps/backend/src/oauth/providers/netsuite.tsx(1 hunks)packages/stack-shared/src/config/schema.ts(2 hunks)packages/stack-shared/src/interface/crud/projects.ts(1 hunks)packages/stack-shared/src/schema-fields.ts(1 hunks)packages/stack-shared/src/utils/oauth.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer ES6 Map over Record when representing key–value collections
Files:
packages/stack-shared/src/schema-fields.tspackages/stack-shared/src/utils/oauth.tsxpackages/stack-shared/src/interface/crud/projects.tsapps/backend/src/lib/projects.tsxapps/backend/src/oauth/index.tsxapps/backend/src/oauth/providers/netsuite.tsxpackages/stack-shared/src/config/schema.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Security Check
🔇 Additional comments (7)
packages/stack-shared/src/schema-fields.ts (1)
512-512: LGTM!The NetSuite account ID schema is properly defined with appropriate OpenAPI metadata, including a clear description and example value. The placement follows the existing pattern by being positioned after the Microsoft tenant ID schema.
packages/stack-shared/src/utils/oauth.tsx (1)
1-1: LGTM!NetSuite is correctly added to the
standardProvidersarray, maintaining alphabetical order and following the established pattern for OAuth providers.apps/backend/src/lib/projects.tsx (1)
186-186: LGTM!The NetSuite account ID is properly mapped from the provider configuration to the environment config override, maintaining consistency with other provider-specific fields like
facebookConfigIdandmicrosoftTenantId.apps/backend/src/oauth/index.tsx (1)
17-17: LGTM!NetSuite provider is correctly integrated into the OAuth system:
- Import statement follows the established pattern
- Provider is registered in the
_providersmapping- Account ID is properly passed to the provider's create method in the standard flow
Also applies to: 35-35, 83-83
packages/stack-shared/src/interface/crud/projects.ts (1)
25-25: LGTM!The
netsuite_account_idfield is correctly added to the OAuth provider read schema, following the established pattern and using the appropriate optional schema.packages/stack-shared/src/config/schema.ts (1)
205-205: LGTM!NetSuite account ID is properly integrated into the configuration schema:
- Added to the environment config schema as an optional field (line 205)
- Included in organization defaults with
undefinedas the default value (line 446)Both changes follow the established patterns for provider-specific configuration fields.
Also applies to: 446-446
apps/backend/src/oauth/providers/netsuite.tsx (1)
31-32: No change required — NetSuite OAuth endpoints are correct.
Authorization endpoint https://${accountId}.app.netsuite.com/app/login/oauth2/authorize.nl (system.netsuite.com as fallback) and token endpoint https://${accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token are valid; some docs also show the token path under <ACCOUNT_ID>.app.netsuite.com.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx (1)
172-179: Add clarification to the Account ID label.The "Account ID" label should specify when this field is required for NetSuite OAuth, similar to how the Facebook and Microsoft fields provide context. For example:
- Facebook: "(only required for Facebook Business)"
- Microsoft: "(required if you are using the organizational directory)"
Consider updating the label to clarify whether this is always required, optional, or conditionally required.
{props.id === 'netsuite' && ( <InputField control={form.control} name="netsuiteAccountId" - label="Account ID" + label="Account ID (required for NetSuite OAuth)" placeholder="Account ID" /> )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx(5 hunks)packages/stack-ui/src/components/brand-icons.tsx(13 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx (2)
packages/stack-shared/src/schema-fields.ts (1)
yupString(187-190)apps/dashboard/src/components/form-fields.tsx (1)
InputField(64-102)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Vercel Agent Review
🔇 Additional comments (6)
packages/stack-ui/src/components/brand-icons.tsx (3)
198-237: LGTM!The NetSuite icon component follows the established pattern used by other provider icons in this file. The implementation is clean and consistent.
283-285: LGTM!The netsuite case is correctly added to the Mapping function and follows the same pattern as other providers.
306-306: LGTM!The toTitle mapping uses the correct "NetSuite" capitalization.
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/auth-methods/providers.tsx (3)
45-45: LGTM!The toTitle mapping correctly adds NetSuite with proper capitalization, consistent with the brand-icons.tsx file.
78-78: LGTM!The default value extraction and submission payload correctly handle
netsuiteAccountId, following the same pattern used for other optional provider-specific fields likefacebookConfigIdandmicrosoftTenantId.Also applies to: 92-92
65-65: Naming consistency confirmed—code is correct.The schema correctly uses
netsuiteAccountId(camelCase) on the frontend. The mapping layer inapps/backend/src/lib/projects.tsx(line 186) properly converts from the API's snake_case format (netsuite_account_idinpackages/stack-shared/src/interface/crud/projects.tsline 25) to the internal camelCase format. This follows the same pattern as existing fields likefacebookConfigIdandmicrosoftTenantId.
| apple: '#000000', | ||
| twitch: '#ffffff' | ||
| twitch: '#ffffff', | ||
| netsuite: '#403C38' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the NetSuite brand color.
The color #403C38 appears to be a dark gray/brown. Please confirm this matches NetSuite's official brand guidelines to ensure consistent branding.
🌐 Web query:
What is the official NetSuite brand color hex code?
💡 Result:
NetSuite’s primary orange (brand) hex is #FF5200. [1][2]
Sources:
[1] NetSuite docs (color palette listing).
[2] Color reference for #FF5200.
Correct the NetSuite brand color to match official guidelines.
NetSuite's primary brand color is #FF5200, not the dark gray/brown #403C38 currently added on line 321. Update this to ensure consistent branding.
🤖 Prompt for AI Agents
In packages/stack-ui/src/components/brand-icons.tsx around line 321, the
NetSuite brand color is incorrectly set to '#403C38'; update that entry so
NetSuite's primary color is the official '#FF5200' (replace the current value
with '#FF5200') to ensure accurate branding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Suggestion:
The NetSuite Account ID is missing from the API response conversion, causing the value to be lost when the dashboard reads the project configuration back from the server.
View Details
📝 Patch Details
diff --git a/apps/backend/src/lib/config.tsx b/apps/backend/src/lib/config.tsx
index 0838f3d4..1bf26c60 100644
--- a/apps/backend/src/lib/config.tsx
+++ b/apps/backend/src/lib/config.tsx
@@ -518,6 +518,7 @@ export const renderedOrganizationConfigToProjectCrud = (renderedConfig: Complete
client_secret: oauthProvider.clientSecret,
facebook_config_id: oauthProvider.facebookConfigId,
microsoft_tenant_id: oauthProvider.microsoftTenantId,
+ netsuite_account_id: oauthProvider.netsuiteAccountId,
} as const) satisfies ProjectsCrud["Admin"]["Read"]['config']['oauth_providers'][number];
})
.filter(isTruthy)
Analysis
NetSuite Account ID lost in API response conversion
What fails: renderedOrganizationConfigToProjectCrud() in apps/backend/src/lib/config.tsx omits netsuite_account_id from OAuth provider mapping, causing data loss when dashboard fetches project configuration
How to reproduce:
};
// Call conversion function
const result = renderedOrganizationConfigToProjectCrud(config);
console.log(result.oauth_providers[0].netsuite_account_id); // undefinedResult: NetSuite Account ID missing from API response - input netsuiteAccountId: 'TEST_ACCOUNT_123' becomes undefined in output netsuite_account_id field
Expected: NetSuite Account ID should be preserved in API response, similar to facebook_config_id and microsoft_tenant_id mappings on lines 519-520
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Suggestion:
The renderedOrganizationConfigToProjectCrud function is missing the netsuite_account_id field when transforming OAuth provider configuration from internal format back to the API format. This causes NetSuite account IDs to be silently dropped from API responses.
View Details
📝 Patch Details
diff --git a/apps/backend/src/lib/config.tsx b/apps/backend/src/lib/config.tsx
index 0838f3d4..1bf26c60 100644
--- a/apps/backend/src/lib/config.tsx
+++ b/apps/backend/src/lib/config.tsx
@@ -518,6 +518,7 @@ export const renderedOrganizationConfigToProjectCrud = (renderedConfig: Complete
client_secret: oauthProvider.clientSecret,
facebook_config_id: oauthProvider.facebookConfigId,
microsoft_tenant_id: oauthProvider.microsoftTenantId,
+ netsuite_account_id: oauthProvider.netsuiteAccountId,
} as const) satisfies ProjectsCrud["Admin"]["Read"]['config']['oauth_providers'][number];
})
.filter(isTruthy)
Analysis
Missing netsuite_account_id field in OAuth provider configuration transformation
What fails: The renderedOrganizationConfigToProjectCrud function in apps/backend/src/lib/config.tsx is missing the netsuite_account_id field when transforming internal OAuth provider configuration (using camelCase netsuiteAccountId) back to API response format (using snake_case).
How to reproduce:
- Configure a NetSuite OAuth provider with an account ID via the API or admin dashboard
- Call the GET project endpoint to retrieve the configuration
- The
netsuite_account_idfield will be missing from the OAuth provider configuration in the response
Result: The netsuite_account_id field is silently omitted from the API response even when it was previously configured in the internal configuration, causing data loss and preventing clients from retrieving their NetSuite OAuth configuration.
Expected: The netsuite_account_id field should be included in the OAuth provider configuration response, consistent with how facebook_config_id and microsoft_tenant_id are already being included.
Fix: Added the missing field mapping in the OAuth provider transformation object at line 520 of apps/backend/src/lib/config.tsx:
- Added
netsuite_account_id: oauthProvider.netsuiteAccountIdto the transformation object
This ensures NetSuite account IDs are properly returned by the API, matching the behavior of other OAuth provider-specific fields defined in the schema (packages/stack-shared/src/interface/crud/projects.ts:25).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Adds a new custom oauth provider for netsuite
Important
Introduces NetSuite as a new OAuth provider, updating relevant schemas and configurations to support it.
NetSuiteProviderclass innetsuite.tsxto handle OAuth with NetSuite, including token fetching and user info processing.getProvider()inindex.tsxto supportnetsuiteas a provider type.netsuiteAccountIdhandling increateOrUpdateProjectWithLegacyConfig()inprojects.tsx.netsuiteAccountIdtoenvironmentConfigSchemainschema.ts.oauthProviderReadSchemaandoauthProviderWriteSchemainprojects.tsto includenetsuite_account_id.oauthNetSuiteAccountIdSchemainschema-fields.ts.netsuitetostandardProvidersinoauth.tsx.This description was created by
for 47025b5. You can customize this summary. It will automatically update as commits are pushed.
Review by RecurseML
🔍 Review performed on 5da45d8..47025b5
✅ Files analyzed, no issues (3)
•
apps/backend/src/oauth/providers/netsuite.tsx•
apps/backend/src/oauth/index.tsx•
apps/backend/src/lib/projects.tsx⏭️ Files skipped (trigger manually) (2)
packages/stack-shared/src/schema-fields.tspackages/stack-shared/src/utils/oauth.tsxSummary by CodeRabbit
New Features
Chores
Tests