Skip to content

Commit e6096c4

Browse files
author
priyanshu.solanki
committed
fix adding client ID and secret fields to supprot ouath
1 parent 7b5405e commit e6096c4

File tree

9 files changed

+272
-39
lines changed

9 files changed

+272
-39
lines changed

apps/docs/components/icons.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,6 +2452,56 @@ export const GeminiIcon = (props: SVGProps<SVGSVGElement>) => (
24522452
</svg>
24532453
)
24542454

2455+
export const VertexIcon = (props: SVGProps<SVGSVGElement>) => (
2456+
<svg
2457+
{...props}
2458+
id='standard_product_icon'
2459+
xmlns='http://www.w3.org/2000/svg'
2460+
version='1.1'
2461+
viewBox='0 0 512 512'
2462+
>
2463+
<g id='bounding_box'>
2464+
<rect width='512' height='512' fill='none' />
2465+
</g>
2466+
<g id='art'>
2467+
<path
2468+
d='M128,244.99c-8.84,0-16-7.16-16-16v-95.97c0-8.84,7.16-16,16-16s16,7.16,16,16v95.97c0,8.84-7.16,16-16,16Z'
2469+
fill='#ea4335'
2470+
/>
2471+
<path
2472+
d='M256,458c-2.98,0-5.97-.83-8.59-2.5l-186-122c-7.46-4.74-9.65-14.63-4.91-22.09,4.75-7.46,14.64-9.65,22.09-4.91l177.41,116.53,177.41-116.53c7.45-4.74,17.34-2.55,22.09,4.91,4.74,7.46,2.55,17.34-4.91,22.09l-186,122c-2.62,1.67-5.61,2.5-8.59,2.5Z'
2473+
fill='#fbbc04'
2474+
/>
2475+
<path
2476+
d='M256,388.03c-8.84,0-16-7.16-16-16v-73.06c0-8.84,7.16-16,16-16s16,7.16,16,16v73.06c0,8.84-7.16,16-16,16Z'
2477+
fill='#34a853'
2478+
/>
2479+
<circle cx='128' cy='70' r='16' fill='#ea4335' />
2480+
<circle cx='128' cy='292' r='16' fill='#ea4335' />
2481+
<path
2482+
d='M384.23,308.01c-8.82,0-15.98-7.14-16-15.97l-.23-94.01c-.02-8.84,7.13-16.02,15.97-16.03h.04c8.82,0,15.98,7.14,16,15.97l.23,94.01c.02,8.84-7.13,16.02-15.97,16.03h-.04Z'
2483+
fill='#4285f4'
2484+
/>
2485+
<circle cx='384' cy='70' r='16' fill='#4285f4' />
2486+
<circle cx='384' cy='134' r='16' fill='#4285f4' />
2487+
<path
2488+
d='M320,220.36c-8.84,0-16-7.16-16-16v-103.02c0-8.84,7.16-16,16-16s16,7.16,16,16v103.02c0,8.84-7.16,16-16,16Z'
2489+
fill='#fbbc04'
2490+
/>
2491+
<circle cx='256' cy='171' r='16' fill='#34a853' />
2492+
<circle cx='256' cy='235' r='16' fill='#34a853' />
2493+
<circle cx='320' cy='265' r='16' fill='#fbbc04' />
2494+
<circle cx='320' cy='329' r='16' fill='#fbbc04' />
2495+
<path
2496+
d='M192,217.36c-8.84,0-16-7.16-16-16v-100.02c0-8.84,7.16-16,16-16s16,7.16,16,16v100.02c0,8.84-7.16,16-16,16Z'
2497+
fill='#fbbc04'
2498+
/>
2499+
<circle cx='192' cy='265' r='16' fill='#fbbc04' />
2500+
<circle cx='192' cy='329' r='16' fill='#fbbc04' />
2501+
</g>
2502+
</svg>
2503+
)
2504+
24552505
export const CerebrasIcon = (props: SVGProps<SVGSVGElement>) => (
24562506
<svg
24572507
{...props}

apps/docs/content/docs/en/tools/translate.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Send a chat completion request to any supported LLM provider
5050
| `maxTokens` | number | No | Maximum tokens in the response |
5151
| `azureEndpoint` | string | No | Azure OpenAI endpoint URL |
5252
| `azureApiVersion` | string | No | Azure OpenAI API version |
53+
| `vertexProject` | string | No | Google Cloud project ID for Vertex AI |
54+
| `vertexLocation` | string | No | Google Cloud location for Vertex AI \(defaults to us-central1\) |
5355

5456
#### Output
5557

apps/sim/app/api/auth/oauth2/callback/servicenow/route.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { type NextRequest, NextResponse } from 'next/server'
22
import { getSession } from '@/lib/auth'
3-
import { env } from '@/lib/core/config/env'
43
import { getBaseUrl } from '@/lib/core/utils/urls'
54
import { createLogger } from '@/lib/logs/console/logger'
65

@@ -34,11 +33,12 @@ export async function GET(request: NextRequest) {
3433
const storedState = request.cookies.get('servicenow_oauth_state')?.value
3534
const storedInstanceUrl = request.cookies.get('servicenow_instance_url')?.value
3635

37-
const clientId = env.SERVICENOW_CLIENT_ID
38-
const clientSecret = env.SERVICENOW_CLIENT_SECRET
36+
// Retrieve client credentials from cookies (set during authorize)
37+
const clientId = request.cookies.get('servicenow_client_id')?.value
38+
const clientSecret = request.cookies.get('servicenow_client_secret')?.value
3939

4040
if (!clientId || !clientSecret) {
41-
logger.error('ServiceNow credentials not configured')
41+
logger.error('ServiceNow client credentials not found in cookies')
4242
return NextResponse.redirect(`${baseUrl}/workspace?error=servicenow_config_error`)
4343
}
4444

@@ -154,9 +154,11 @@ export async function GET(request: NextRequest) {
154154
})
155155
}
156156

157-
// Clean up OAuth state cookies
157+
// Clean up OAuth state and credentials cookies
158158
response.cookies.delete('servicenow_oauth_state')
159159
response.cookies.delete('servicenow_instance_url')
160+
response.cookies.delete('servicenow_client_id')
161+
response.cookies.delete('servicenow_client_secret')
160162

161163
return response
162164
} catch (error) {

apps/sim/app/api/auth/servicenow/authorize/route.ts

Lines changed: 87 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { type NextRequest, NextResponse } from 'next/server'
22
import { getSession } from '@/lib/auth'
3-
import { env } from '@/lib/core/config/env'
43
import { getBaseUrl } from '@/lib/core/utils/urls'
54
import { createLogger } from '@/lib/logs/console/logger'
65

@@ -38,17 +37,13 @@ export async function GET(request: NextRequest) {
3837
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
3938
}
4039

41-
const clientId = env.SERVICENOW_CLIENT_ID
42-
43-
if (!clientId) {
44-
logger.error('SERVICENOW_CLIENT_ID not configured')
45-
return NextResponse.json({ error: 'ServiceNow client ID not configured' }, { status: 500 })
46-
}
47-
4840
const instanceUrl = request.nextUrl.searchParams.get('instanceUrl')
41+
const clientId = request.nextUrl.searchParams.get('clientId')
42+
const clientSecret = request.nextUrl.searchParams.get('clientSecret')
4943
const returnUrl = request.nextUrl.searchParams.get('returnUrl')
5044

51-
if (!instanceUrl) {
45+
// If any required parameter is missing, show the form
46+
if (!instanceUrl || !clientId || !clientSecret) {
5247
const returnUrlParam = returnUrl ? encodeURIComponent(returnUrl) : ''
5348
return new NextResponse(
5449
`<!DOCTYPE html>
@@ -63,9 +58,11 @@ export async function GET(request: NextRequest) {
6358
display: flex;
6459
align-items: center;
6560
justify-content: center;
66-
height: 100vh;
61+
min-height: 100vh;
6762
margin: 0;
6863
background: linear-gradient(135deg, #81B5A1 0%, #5A8A75 100%);
64+
padding: 20px;
65+
box-sizing: border-box;
6966
}
7067
.container {
7168
background: white;
@@ -74,7 +71,7 @@ export async function GET(request: NextRequest) {
7471
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
7572
text-align: center;
7673
max-width: 450px;
77-
width: 90%;
74+
width: 100%;
7875
}
7976
h2 {
8077
color: #111827;
@@ -84,13 +81,23 @@ export async function GET(request: NextRequest) {
8481
color: #6b7280;
8582
margin: 0 0 1.5rem 0;
8683
}
84+
.form-group {
85+
text-align: left;
86+
margin-bottom: 1rem;
87+
}
88+
label {
89+
display: block;
90+
font-size: 0.875rem;
91+
font-weight: 500;
92+
color: #374151;
93+
margin-bottom: 0.25rem;
94+
}
8795
input {
8896
width: 100%;
8997
padding: 0.75rem;
9098
border: 1px solid #d1d5db;
9199
border-radius: 8px;
92100
font-size: 1rem;
93-
margin-bottom: 1rem;
94101
box-sizing: border-box;
95102
}
96103
input:focus {
@@ -108,14 +115,15 @@ export async function GET(request: NextRequest) {
108115
font-size: 1rem;
109116
cursor: pointer;
110117
font-weight: 500;
118+
margin-top: 0.5rem;
111119
}
112120
button:hover {
113121
background: #6A9A87;
114122
}
115123
.help {
116-
font-size: 0.875rem;
124+
font-size: 0.75rem;
117125
color: #9ca3af;
118-
margin-top: 1rem;
126+
margin-top: 0.25rem;
119127
}
120128
.error {
121129
color: #dc2626;
@@ -128,18 +136,41 @@ export async function GET(request: NextRequest) {
128136
<body>
129137
<div class="container">
130138
<h2>Connect Your ServiceNow Instance</h2>
131-
<p>Enter your ServiceNow instance URL to continue</p>
139+
<p>Enter your ServiceNow credentials to continue</p>
132140
<div id="error" class="error"></div>
133141
<form onsubmit="handleSubmit(event)">
134-
<input
135-
type="text"
136-
id="instanceUrl"
137-
placeholder="https://mycompany.service-now.com"
138-
required
139-
/>
142+
<div class="form-group">
143+
<label for="instanceUrl">Instance URL</label>
144+
<input
145+
type="text"
146+
id="instanceUrl"
147+
placeholder="https://mycompany.service-now.com"
148+
required
149+
/>
150+
<p class="help">Your ServiceNow instance URL (e.g., https://yourcompany.service-now.com)</p>
151+
</div>
152+
<div class="form-group">
153+
<label for="clientId">Client ID</label>
154+
<input
155+
type="text"
156+
id="clientId"
157+
placeholder="Enter your OAuth Client ID"
158+
required
159+
/>
160+
<p class="help">OAuth Client ID from your ServiceNow Application Registry</p>
161+
</div>
162+
<div class="form-group">
163+
<label for="clientSecret">Client Secret</label>
164+
<input
165+
type="password"
166+
id="clientSecret"
167+
placeholder="Enter your OAuth Client Secret"
168+
required
169+
/>
170+
<p class="help">OAuth Client Secret from your ServiceNow Application Registry</p>
171+
</div>
140172
<button type="submit">Connect Instance</button>
141173
</form>
142-
<p class="help">Your instance URL looks like: https://yourcompany.service-now.com</p>
143174
</div>
144175
145176
<script>
@@ -148,6 +179,8 @@ export async function GET(request: NextRequest) {
148179
e.preventDefault();
149180
const errorEl = document.getElementById('error');
150181
let instanceUrl = document.getElementById('instanceUrl').value.trim();
182+
const clientId = document.getElementById('clientId').value.trim();
183+
const clientSecret = document.getElementById('clientSecret').value.trim();
151184
152185
// Ensure https:// prefix
153186
if (!instanceUrl.startsWith('https://') && !instanceUrl.startsWith('http://')) {
@@ -170,7 +203,21 @@ export async function GET(request: NextRequest) {
170203
return;
171204
}
172205
206+
if (!clientId) {
207+
errorEl.textContent = 'Please enter your Client ID';
208+
errorEl.style.display = 'block';
209+
return;
210+
}
211+
212+
if (!clientSecret) {
213+
errorEl.textContent = 'Please enter your Client Secret';
214+
errorEl.style.display = 'block';
215+
return;
216+
}
217+
173218
let url = window.location.pathname + '?instanceUrl=' + encodeURIComponent(instanceUrl);
219+
url += '&clientId=' + encodeURIComponent(clientId);
220+
url += '&clientSecret=' + encodeURIComponent(clientSecret);
174221
if (returnUrl) {
175222
url += '&returnUrl=' + returnUrl;
176223
}
@@ -229,7 +276,7 @@ export async function GET(request: NextRequest) {
229276

230277
const response = NextResponse.redirect(oauthUrl)
231278

232-
// Store state and instance URL in cookies for validation in callback
279+
// Store state, instance URL, and credentials in cookies for validation in callback
233280
response.cookies.set('servicenow_oauth_state', state, {
234281
httpOnly: true,
235282
secure: process.env.NODE_ENV === 'production',
@@ -246,6 +293,23 @@ export async function GET(request: NextRequest) {
246293
path: '/',
247294
})
248295

296+
// Store client credentials in cookies for the callback to use
297+
response.cookies.set('servicenow_client_id', clientId, {
298+
httpOnly: true,
299+
secure: process.env.NODE_ENV === 'production',
300+
sameSite: 'lax',
301+
maxAge: 60 * 10,
302+
path: '/',
303+
})
304+
305+
response.cookies.set('servicenow_client_secret', clientSecret, {
306+
httpOnly: true,
307+
secure: process.env.NODE_ENV === 'production',
308+
sameSite: 'lax',
309+
maxAge: 60 * 10,
310+
path: '/',
311+
})
312+
249313
if (returnUrl) {
250314
response.cookies.set('servicenow_return_url', returnUrl, {
251315
httpOnly: true,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ export interface OAuthRequiredModalProps {
2222
requiredScopes?: string[]
2323
serviceId?: string
2424
newScopes?: string[]
25+
servicenowCredentials?: {
26+
instanceUrl: string
27+
clientId: string
28+
clientSecret: string
29+
}
2530
}
2631

2732
const SCOPE_DESCRIPTIONS: Record<string, string> = {
@@ -297,6 +302,7 @@ export function OAuthRequiredModal({
297302
requiredScopes = [],
298303
serviceId,
299304
newScopes = [],
305+
servicenowCredentials,
300306
}: OAuthRequiredModalProps) {
301307
const effectiveServiceId = serviceId || getServiceIdFromScopes(provider, requiredScopes)
302308
const { baseProvider } = parseProvider(provider)
@@ -348,9 +354,24 @@ export function OAuthRequiredModal({
348354
}
349355

350356
if (providerId === 'servicenow') {
351-
// Pass the current URL so we can redirect back after OAuth
357+
// ServiceNow requires credentials from the block
358+
if (
359+
!servicenowCredentials?.instanceUrl ||
360+
!servicenowCredentials?.clientId ||
361+
!servicenowCredentials?.clientSecret
362+
) {
363+
// If credentials are missing, redirect to authorize which will show a form
364+
const returnUrl = encodeURIComponent(window.location.href)
365+
window.location.href = `/api/auth/servicenow/authorize?returnUrl=${returnUrl}`
366+
return
367+
}
368+
369+
// Pass the current URL and credentials so we can redirect back after OAuth
352370
const returnUrl = encodeURIComponent(window.location.href)
353-
window.location.href = `/api/auth/servicenow/authorize?returnUrl=${returnUrl}`
371+
const instanceUrl = encodeURIComponent(servicenowCredentials.instanceUrl)
372+
const clientId = encodeURIComponent(servicenowCredentials.clientId)
373+
const clientSecret = encodeURIComponent(servicenowCredentials.clientSecret)
374+
window.location.href = `/api/auth/servicenow/authorize?returnUrl=${returnUrl}&instanceUrl=${instanceUrl}&clientId=${clientId}&clientSecret=${clientSecret}`
354375
return
355376
}
356377

0 commit comments

Comments
 (0)