1+ import { safeStringify , generateJsonResponse } from "./common" ;
12const { jwtAuth } = await import ( './auth' ) ;
2- const responses = await import ( './responses' ) ;
33const { ValueMapper } = await import ( './mapping' ) ;
44const { setCorsHeaders } = await import ( './cors' ) ;
55const { PathOperator } = await import ( './path-ops' ) ;
66const { AuthError } = await import ( './types/error_types' ) ;
77const { setPoweredByHeader } = await import ( './powered-by' ) ;
88const { createProxiedRequest } = await import ( './requests' ) ;
99const { IntegrationTypeEnum } = await import ( './enums/integration-type' ) ;
10- const { auth0CallbackHandler, validateIdToken, getProfile, redirectToLogin } = await import ( './integrations/auth0' ) ;
1110const { ServerlessAPIGatewayContext } = await import ( './types/serverless_api_gateway_context' ) ;
12-
11+ const { auth0CallbackHandler , validateIdToken , getProfile , redirectToLogin , refreshToken } = await import ( './integrations/auth0' ) ;
1312
1413export default {
1514 async fetch ( request , env , ctx ) {
@@ -69,7 +68,7 @@ export default {
6968 return setPoweredByHeader (
7069 setCorsHeaders (
7170 request ,
72- new Response ( JSON . stringify ( { error : error . message , code : error . code } ) , {
71+ new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
7372 status : error . statusCode ,
7473 headers : { 'Content-Type' : 'application/json' } ,
7574 } ) ,
@@ -83,13 +82,13 @@ export default {
8382 }
8483 else if ( sagContext . apiConfig . authorizer && matchedPath . config . auth && sagContext . apiConfig . authorizer . type == 'auth0' ) {
8584 try {
86- sagContext . jwtPayload = await validateIdToken ( request , sagContext . apiConfig . authorizer ) ;
85+ sagContext . jwtPayload = await validateIdToken ( request , null , sagContext . apiConfig . authorizer ) ;
8786 } catch ( error ) {
8887 if ( error instanceof AuthError ) {
8988 return setPoweredByHeader (
9089 setCorsHeaders (
9190 request ,
92- new Response ( JSON . stringify ( { error : error . message , code : error . code } ) , {
91+ new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
9392 status : error . statusCode ,
9493 headers : { 'Content-Type' : 'application/json' } ,
9594 } ) ,
@@ -128,23 +127,88 @@ export default {
128127 const module = await import ( `${ service . entrypoint } .js` ) ;
129128 const Service = module . default ;
130129 const serviceInstance = new Service ( ) ;
131- const response = serviceInstance . fetch ( request , env , ctx ) ;
132- return setPoweredByHeader ( setCorsHeaders ( request , response , sagContext . apiConfig . cors ) ) ;
130+ const response = await serviceInstance . fetch ( request , env , ctx ) ;
131+ try {
132+ return setPoweredByHeader ( setCorsHeaders ( request , generateJsonResponse ( response ) , sagContext . apiConfig . cors ) ) ;
133+ } catch ( error ) {
134+ return setPoweredByHeader (
135+ setCorsHeaders (
136+ request ,
137+ new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
138+ status : error . statusCode || 500 ,
139+ headers : { 'Content-Type' : 'application/json' } ,
140+ } ) ,
141+ sagContext . apiConfig . cors
142+ )
143+ ) ;
144+ }
133145 }
134146 } else if ( matchedPath . config . integration && matchedPath . config . integration . type == IntegrationTypeEnum . SERVICE_BINDING ) {
135147 const service =
136148 sagContext . apiConfig . serviceBindings &&
137149 sagContext . apiConfig . serviceBindings . find ( ( serviceBinding ) => serviceBinding . alias === matchedPath . config . integration . binding ) ;
138150
139151 if ( service ) {
140- const response = await env [ service . binding ] [ matchedPath . config . integration . function ] ( request , JSON . stringify ( env ) , JSON . stringify ( sagContext ) ) ;
141- return setPoweredByHeader ( setCorsHeaders ( request , response , sagContext . apiConfig . cors ) ) ;
152+ try {
153+ const response = await env [ service . binding ] [ matchedPath . config . integration . function ] ( request , safeStringify ( env ) , safeStringify ( sagContext ) ) ;
154+ return setPoweredByHeader ( setCorsHeaders ( request , generateJsonResponse ( response ) , sagContext . apiConfig . cors ) ) ;
155+ } catch ( error ) {
156+ return setPoweredByHeader (
157+ setCorsHeaders (
158+ request ,
159+ new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
160+ status : error . statusCode || 500 ,
161+ headers : { 'Content-Type' : 'application/json' } ,
162+ } ) ,
163+ sagContext . apiConfig . cors
164+ )
165+ ) ;
166+ }
142167 }
143168 } else if ( matchedPath . config . integration && matchedPath . config . integration . type == IntegrationTypeEnum . AUTH0CALLBACK ) {
144- const urlParams = new URLSearchParams ( sagContext . requestUrl . search ) ;
145- const code = urlParams . get ( 'code' ) ;
169+ try {
170+ const urlParams = new URLSearchParams ( sagContext . requestUrl . search ) ;
171+ const code = urlParams . get ( 'code' ) ;
172+
173+ const jwt = await auth0CallbackHandler ( code , sagContext . apiConfig . authorizer ) ;
174+ sagContext . jwtPayload = await validateIdToken ( null , jwt . id_token , sagContext . apiConfig . authorizer ) ;
175+
176+ // Post-process logic
177+ if ( matchedPath . config . integration . post_process ) {
178+ const postProcessConfig = matchedPath . config . integration . post_process ;
179+ if ( postProcessConfig . type === 'service_binding' ) {
180+ const postProcessService = sagContext . apiConfig . serviceBindings . find (
181+ ( serviceBinding ) => serviceBinding . alias === postProcessConfig . binding
182+ ) ;
183+ if ( postProcessService ) {
184+ await env [ postProcessService . binding ] [ postProcessConfig . function ] ( request , safeStringify ( env ) , safeStringify ( sagContext ) ) ;
185+ }
186+ }
187+ }
146188
147- return auth0CallbackHandler ( code , sagContext . apiConfig . authorizer ) ;
189+ return setPoweredByHeader ( setCorsHeaders (
190+ request ,
191+ new Response ( safeStringify ( jwt ) , {
192+ status : 200 ,
193+ headers : { 'Content-Type' : 'application/json' } ,
194+ } ) ,
195+ sagContext . apiConfig . cors
196+ ) ) ;
197+ } catch ( error ) {
198+ console . error ( 'Error processing Auth0 callback' , error ) ;
199+ if ( error instanceof AuthError ) {
200+ return setPoweredByHeader ( setCorsHeaders (
201+ request ,
202+ new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
203+ status : error . statusCode ,
204+ headers : { 'Content-Type' : 'application/json' } ,
205+ } ) ,
206+ sagContext . apiConfig . cors
207+ ) ) ;
208+ } else {
209+ return setPoweredByHeader ( setCorsHeaders ( request , responses . internalServerErrorResponse ( ) , sagContext . apiConfig . cors ) ) ;
210+ }
211+ }
148212 } else if ( matchedPath . config . integration && matchedPath . config . integration . type == IntegrationTypeEnum . AUTH0USERINFO ) {
149213 const urlParams = new URLSearchParams ( sagContext . requestUrl . search ) ;
150214 const accessToken = urlParams . get ( 'access_token' ) ;
@@ -153,11 +217,13 @@ export default {
153217 } else if ( matchedPath . config . integration && matchedPath . config . integration . type == IntegrationTypeEnum . AUTH0CALLBACKREDIRECT ) {
154218 const urlParams = new URLSearchParams ( sagContext . requestUrl . search ) ;
155219 return redirectToLogin ( { state : urlParams . get ( 'state' ) } , sagContext . apiConfig . authorizer ) ;
220+ } else if ( matchedPath . config . integration && matchedPath . config . integration . type == IntegrationTypeEnum . AUTH0REFRESH ) {
221+ return this . refreshTokenLogic ( request , env , sagContext ) ;
156222 } else {
157223 return setPoweredByHeader (
158224 setCorsHeaders (
159225 request ,
160- new Response ( JSON . stringify ( matchedPath . config . response ) , { headers : { 'Content-Type' : 'application/json' } } ) ,
226+ new Response ( safeStringify ( matchedPath . config . response ) , { headers : { 'Content-Type' : 'application/json' } } ) ,
161227 sagContext . apiConfig . cors
162228 ) ,
163229 ) ;
@@ -185,4 +251,56 @@ export default {
185251
186252 return apiConfig ;
187253 } ,
254+
255+ async refreshTokenLogic ( request , env , sagContext ) {
256+ const urlParams = new URLSearchParams ( sagContext . requestUrl . search ) ;
257+ const refreshTokenParam = urlParams . get ( 'refresh_token' ) ;
258+
259+ if ( ! refreshTokenParam ) {
260+ return setPoweredByHeader ( setCorsHeaders ( request ,
261+ new Response (
262+ safeStringify ( { error : 'Missing refresh token' , code : 'missing_refresh_token' } ) ,
263+ { status : 400 , headers : { 'Content-Type' : 'application/json' } }
264+ ) ,
265+ sagContext . apiConfig . cors ) ) ;
266+ }
267+
268+ try {
269+ sagContext . jwtPayload = await validateIdToken ( request , null , sagContext . apiConfig . authorizer ) ;
270+ return setPoweredByHeader ( setCorsHeaders ( request ,
271+ new Response (
272+ safeStringify ( { message : 'Token is still valid' , code : 'token_still_valid' } ) ,
273+ { status : 200 , headers : { 'Content-Type' : 'application/json' } }
274+ ) ,
275+ sagContext . apiConfig . cors ) ) ;
276+
277+ } catch ( error ) {
278+ if ( error instanceof AuthError && error . code === 'ERR_JWT_EXPIRED' ) {
279+ try {
280+ const newTokens = await refreshToken ( refreshTokenParam , sagContext . apiConfig . authorizer ) ;
281+ return setPoweredByHeader ( setCorsHeaders (
282+ request ,
283+ new Response ( safeStringify ( newTokens ) , { status : 200 , headers : { 'Content-Type' : 'application/json' } , } ) ,
284+ sagContext . apiConfig . cors
285+ ) ) ;
286+ } catch ( refreshError ) {
287+ return setPoweredByHeader ( setCorsHeaders (
288+ request ,
289+ new Response ( safeStringify ( { error : refreshError . message , code : refreshError . code } ) , {
290+ status : refreshError . statusCode || 500 , headers : { 'Content-Type' : 'application/json' } ,
291+ } ) ,
292+ sagContext . apiConfig . cors
293+ ) ) ;
294+ }
295+ } else {
296+ return setPoweredByHeader (
297+ setCorsHeaders (
298+ request , new Response ( safeStringify ( { error : error . message , code : error . code } ) , {
299+ status : error . statusCode || 500 , headers : { 'Content-Type' : 'application/json' } ,
300+ } ) ,
301+ sagContext . apiConfig . cors
302+ ) ) ;
303+ }
304+ }
305+ }
188306} ;
0 commit comments