@@ -16,6 +16,63 @@ export interface AuthResult {
1616 error ?: string
1717}
1818
19+ /**
20+ * Resolves userId from a verified internal JWT token.
21+ * Extracts workflowId/userId from URL params or POST body, then looks up userId if needed.
22+ */
23+ async function resolveUserFromJwt (
24+ request : NextRequest ,
25+ verificationUserId : string | null ,
26+ options : { requireWorkflowId ?: boolean }
27+ ) : Promise < AuthResult > {
28+ let workflowId : string | null = null
29+ let userId : string | null = verificationUserId
30+
31+ const { searchParams } = new URL ( request . url )
32+ workflowId = searchParams . get ( 'workflowId' )
33+ if ( ! userId ) {
34+ userId = searchParams . get ( 'userId' )
35+ }
36+
37+ if ( ! workflowId && ! userId && request . method === 'POST' ) {
38+ try {
39+ const clonedRequest = request . clone ( )
40+ const bodyText = await clonedRequest . text ( )
41+ if ( bodyText ) {
42+ const body = JSON . parse ( bodyText )
43+ workflowId = body . workflowId || body . _context ?. workflowId
44+ userId = userId || body . userId || body . _context ?. userId
45+ }
46+ } catch {
47+ // Ignore JSON parse errors
48+ }
49+ }
50+
51+ if ( userId ) {
52+ return { success : true , userId, authType : 'internal_jwt' }
53+ }
54+
55+ if ( workflowId ) {
56+ const [ workflowData ] = await db
57+ . select ( { userId : workflow . userId } )
58+ . from ( workflow )
59+ . where ( eq ( workflow . id , workflowId ) )
60+ . limit ( 1 )
61+
62+ if ( ! workflowData ) {
63+ return { success : false , error : 'Workflow not found' }
64+ }
65+
66+ return { success : true , userId : workflowData . userId , authType : 'internal_jwt' }
67+ }
68+
69+ if ( options . requireWorkflowId !== false ) {
70+ return { success : false , error : 'workflowId or userId required for internal JWT calls' }
71+ }
72+
73+ return { success : true , authType : 'internal_jwt' }
74+ }
75+
1976/**
2077 * Check for internal JWT authentication only.
2178 * Use this for routes that should ONLY be accessible by the executor (server-to-server).
@@ -51,75 +108,10 @@ export async function checkInternalAuth(
51108 const verification = await verifyInternalToken ( token )
52109
53110 if ( ! verification . valid ) {
54- return {
55- success : false ,
56- error : 'Invalid internal token' ,
57- }
58- }
59-
60- let workflowId : string | null = null
61- let userId : string | null = verification . userId || null
62-
63- const { searchParams } = new URL ( request . url )
64- workflowId = searchParams . get ( 'workflowId' )
65- if ( ! userId ) {
66- userId = searchParams . get ( 'userId' )
67- }
68-
69- if ( ! workflowId && ! userId && request . method === 'POST' ) {
70- try {
71- const clonedRequest = request . clone ( )
72- const bodyText = await clonedRequest . text ( )
73- if ( bodyText ) {
74- const body = JSON . parse ( bodyText )
75- workflowId = body . workflowId || body . _context ?. workflowId
76- userId = userId || body . userId || body . _context ?. userId
77- }
78- } catch {
79- // Ignore JSON parse errors
80- }
81- }
82-
83- if ( userId ) {
84- return {
85- success : true ,
86- userId,
87- authType : 'internal_jwt' ,
88- }
89- }
90-
91- if ( workflowId ) {
92- const [ workflowData ] = await db
93- . select ( { userId : workflow . userId } )
94- . from ( workflow )
95- . where ( eq ( workflow . id , workflowId ) )
96- . limit ( 1 )
97-
98- if ( ! workflowData ) {
99- return {
100- success : false ,
101- error : 'Workflow not found' ,
102- }
103- }
104-
105- return {
106- success : true ,
107- userId : workflowData . userId ,
108- authType : 'internal_jwt' ,
109- }
111+ return { success : false , error : 'Invalid internal token' }
110112 }
111113
112- if ( options . requireWorkflowId !== false ) {
113- return {
114- success : false ,
115- error : 'workflowId or userId required for internal JWT calls' ,
116- }
117- }
118-
119- return {
120- success : true ,
121- authType : 'internal_jwt' ,
122- }
114+ return resolveUserFromJwt ( request , verification . userId || null , options )
123115 } catch ( error ) {
124116 logger . error ( 'Error in internal authentication:' , error )
125117 return {
@@ -159,69 +151,7 @@ export async function checkSessionOrInternalAuth(
159151 const verification = await verifyInternalToken ( token )
160152
161153 if ( verification . valid ) {
162- let workflowId : string | null = null
163- let userId : string | null = verification . userId || null
164-
165- const { searchParams } = new URL ( request . url )
166- workflowId = searchParams . get ( 'workflowId' )
167- if ( ! userId ) {
168- userId = searchParams . get ( 'userId' )
169- }
170-
171- if ( ! workflowId && ! userId && request . method === 'POST' ) {
172- try {
173- const clonedRequest = request . clone ( )
174- const bodyText = await clonedRequest . text ( )
175- if ( bodyText ) {
176- const body = JSON . parse ( bodyText )
177- workflowId = body . workflowId || body . _context ?. workflowId
178- userId = userId || body . userId || body . _context ?. userId
179- }
180- } catch {
181- // Ignore JSON parse errors
182- }
183- }
184-
185- if ( userId ) {
186- return {
187- success : true ,
188- userId,
189- authType : 'internal_jwt' ,
190- }
191- }
192-
193- if ( workflowId ) {
194- const [ workflowData ] = await db
195- . select ( { userId : workflow . userId } )
196- . from ( workflow )
197- . where ( eq ( workflow . id , workflowId ) )
198- . limit ( 1 )
199-
200- if ( ! workflowData ) {
201- return {
202- success : false ,
203- error : 'Workflow not found' ,
204- }
205- }
206-
207- return {
208- success : true ,
209- userId : workflowData . userId ,
210- authType : 'internal_jwt' ,
211- }
212- }
213-
214- if ( options . requireWorkflowId !== false ) {
215- return {
216- success : false ,
217- error : 'workflowId or userId required for internal JWT calls' ,
218- }
219- }
220-
221- return {
222- success : true ,
223- authType : 'internal_jwt' ,
224- }
154+ return resolveUserFromJwt ( request , verification . userId || null , options )
225155 }
226156 }
227157
@@ -268,70 +198,7 @@ export async function checkHybridAuth(
268198 const verification = await verifyInternalToken ( token )
269199
270200 if ( verification . valid ) {
271- let workflowId : string | null = null
272- let userId : string | null = verification . userId || null
273-
274- const { searchParams } = new URL ( request . url )
275- workflowId = searchParams . get ( 'workflowId' )
276- if ( ! userId ) {
277- userId = searchParams . get ( 'userId' )
278- }
279-
280- if ( ! workflowId && ! userId && request . method === 'POST' ) {
281- try {
282- // Clone the request to avoid consuming the original body
283- const clonedRequest = request . clone ( )
284- const bodyText = await clonedRequest . text ( )
285- if ( bodyText ) {
286- const body = JSON . parse ( bodyText )
287- workflowId = body . workflowId || body . _context ?. workflowId
288- userId = userId || body . userId || body . _context ?. userId
289- }
290- } catch {
291- // Ignore JSON parse errors
292- }
293- }
294-
295- if ( userId ) {
296- return {
297- success : true ,
298- userId,
299- authType : 'internal_jwt' ,
300- }
301- }
302-
303- if ( workflowId ) {
304- const [ workflowData ] = await db
305- . select ( { userId : workflow . userId } )
306- . from ( workflow )
307- . where ( eq ( workflow . id , workflowId ) )
308- . limit ( 1 )
309-
310- if ( ! workflowData ) {
311- return {
312- success : false ,
313- error : 'Workflow not found' ,
314- }
315- }
316-
317- return {
318- success : true ,
319- userId : workflowData . userId ,
320- authType : 'internal_jwt' ,
321- }
322- }
323-
324- if ( options . requireWorkflowId !== false ) {
325- return {
326- success : false ,
327- error : 'workflowId or userId required for internal JWT calls' ,
328- }
329- }
330-
331- return {
332- success : true ,
333- authType : 'internal_jwt' ,
334- }
201+ return resolveUserFromJwt ( request , verification . userId || null , options )
335202 }
336203 }
337204
0 commit comments