@@ -29,30 +29,70 @@ export type AuthenticatedEnvironment = Optional<
2929  "orgMember" 
3030> ; 
3131
32- export  type  ApiAuthenticationResult  =  { 
32+ export  type  ApiAuthenticationResult  = 
33+   |  ApiAuthenticationResultSuccess 
34+   |  ApiAuthenticationResultFailure ; 
35+ 
36+ export  type  ApiAuthenticationResultSuccess  =  { 
37+   ok : true ; 
3338  apiKey : string ; 
3439  type : "PUBLIC"  |  "PRIVATE"  |  "PUBLIC_JWT" ; 
3540  environment : AuthenticatedEnvironment ; 
3641  scopes ?: string [ ] ; 
3742} ; 
3843
44+ export  type  ApiAuthenticationResultFailure  =  { 
45+   ok : false ; 
46+   error : string ; 
47+ } ; 
48+ 
49+ /** 
50+  * @deprecated  Use `authenticateApiRequestWithFailure` instead. 
51+  */ 
3952export  async  function  authenticateApiRequest ( 
4053  request : Request , 
4154  options : {  allowPublicKey ?: boolean ;  allowJWT ?: boolean  }  =  { } 
42- ) : Promise < ApiAuthenticationResult  |  undefined >  { 
55+ ) : Promise < ApiAuthenticationResultSuccess  |  undefined >  { 
4356  const  apiKey  =  getApiKeyFromRequest ( request ) ; 
4457
4558  if  ( ! apiKey )  { 
4659    return ; 
4760  } 
4861
49-   return  authenticateApiKey ( apiKey ,  options ) ; 
62+   const  authentication  =  await  authenticateApiKey ( apiKey ,  options ) ; 
63+ 
64+   return  authentication ; 
5065} 
5166
67+ /** 
68+  * This method is the same as `authenticateApiRequest` but it returns a failure result instead of undefined. 
69+  * It should be used from now on to ensure that the API key is always validated and provide a failure result. 
70+  */ 
71+ export  async  function  authenticateApiRequestWithFailure ( 
72+   request : Request , 
73+   options : {  allowPublicKey ?: boolean ;  allowJWT ?: boolean  }  =  { } 
74+ ) : Promise < ApiAuthenticationResult >  { 
75+   const  apiKey  =  getApiKeyFromRequest ( request ) ; 
76+ 
77+   if  ( ! apiKey )  { 
78+     return  { 
79+       ok : false , 
80+       error : "Invalid API Key" , 
81+     } ; 
82+   } 
83+ 
84+   const  authentication  =  await  authenticateApiKeyWithFailure ( apiKey ,  options ) ; 
85+ 
86+   return  authentication ; 
87+ } 
88+ 
89+ /** 
90+  * @deprecated  Use `authenticateApiKeyWithFailure` instead. 
91+  */ 
5292export  async  function  authenticateApiKey ( 
5393  apiKey : string , 
5494  options : {  allowPublicKey ?: boolean ;  allowJWT ?: boolean  }  =  { } 
55- ) : Promise < ApiAuthenticationResult  |  undefined >  { 
95+ ) : Promise < ApiAuthenticationResultSuccess  |  undefined >  { 
5696  const  result  =  getApiKeyResult ( apiKey ) ; 
5797
5898  if  ( ! result )  { 
@@ -70,30 +110,120 @@ export async function authenticateApiKey(
70110  switch  ( result . type )  { 
71111    case  "PUBLIC" : { 
72112      const  environment  =  await  findEnvironmentByPublicApiKey ( result . apiKey ) ; 
73-       if  ( ! environment )  return ; 
113+       if  ( ! environment )  { 
114+         return ; 
115+       } 
116+ 
74117      return  { 
118+         ok : true , 
75119        ...result , 
76120        environment, 
77121      } ; 
78122    } 
79123    case  "PRIVATE" : { 
80124      const  environment  =  await  findEnvironmentByApiKey ( result . apiKey ) ; 
81-       if  ( ! environment )  return ; 
125+       if  ( ! environment )  { 
126+         return ; 
127+       } 
128+ 
82129      return  { 
130+         ok : true , 
83131        ...result , 
84132        environment, 
85133      } ; 
86134    } 
87135    case  "PUBLIC_JWT" : { 
88136      const  validationResults  =  await  validatePublicJwtKey ( result . apiKey ) ; 
89137
90-       if  ( ! validationResults )  { 
138+       if  ( ! validationResults . ok )  { 
91139        return ; 
92140      } 
93141
94142      const  parsedClaims  =  ClaimsSchema . safeParse ( validationResults . claims ) ; 
95143
96144      return  { 
145+         ok : true , 
146+         ...result , 
147+         environment : validationResults . environment , 
148+         scopes : parsedClaims . success  ? parsedClaims . data . scopes  : [ ] , 
149+       } ; 
150+     } 
151+   } 
152+ } 
153+ 
154+ /** 
155+  * This method is the same as `authenticateApiKey` but it returns a failure result instead of undefined. 
156+  * It should be used from now on to ensure that the API key is always validated and provide a failure result. 
157+  */ 
158+ export  async  function  authenticateApiKeyWithFailure ( 
159+   apiKey : string , 
160+   options : {  allowPublicKey ?: boolean ;  allowJWT ?: boolean  }  =  { } 
161+ ) : Promise < ApiAuthenticationResult >  { 
162+   const  result  =  getApiKeyResult ( apiKey ) ; 
163+ 
164+   if  ( ! result )  { 
165+     return  { 
166+       ok : false , 
167+       error : "Invalid API Key" , 
168+     } ; 
169+   } 
170+ 
171+   if  ( ! options . allowPublicKey  &&  result . type  ===  "PUBLIC" )  { 
172+     return  { 
173+       ok : false , 
174+       error : "Public API keys are not allowed for this request" , 
175+     } ; 
176+   } 
177+ 
178+   if  ( ! options . allowJWT  &&  result . type  ===  "PUBLIC_JWT" )  { 
179+     return  { 
180+       ok : false , 
181+       error : "Public JWT API keys are not allowed for this request" , 
182+     } ; 
183+   } 
184+ 
185+   switch  ( result . type )  { 
186+     case  "PUBLIC" : { 
187+       const  environment  =  await  findEnvironmentByPublicApiKey ( result . apiKey ) ; 
188+       if  ( ! environment )  { 
189+         return  { 
190+           ok : false , 
191+           error : "Invalid API Key" , 
192+         } ; 
193+       } 
194+ 
195+       return  { 
196+         ok : true , 
197+         ...result , 
198+         environment, 
199+       } ; 
200+     } 
201+     case  "PRIVATE" : { 
202+       const  environment  =  await  findEnvironmentByApiKey ( result . apiKey ) ; 
203+       if  ( ! environment )  { 
204+         return  { 
205+           ok : false , 
206+           error : "Invalid API Key" , 
207+         } ; 
208+       } 
209+ 
210+       return  { 
211+         ok : true , 
212+         ...result , 
213+         environment, 
214+       } ; 
215+     } 
216+     case  "PUBLIC_JWT" : { 
217+       const  validationResults  =  await  validatePublicJwtKey ( result . apiKey ) ; 
218+ 
219+       if  ( ! validationResults . ok )  { 
220+         return  validationResults ; 
221+       } 
222+ 
223+       const  parsedClaims  =  ClaimsSchema . safeParse ( validationResults . claims ) ; 
224+ 
225+       return  { 
226+         ok : true , 
97227        ...result , 
98228        environment : validationResults . environment , 
99229        scopes : parsedClaims . success  ? parsedClaims . data . scopes  : [ ] , 
@@ -207,6 +337,10 @@ export async function authenticatedEnvironmentForAuthentication(
207337
208338  switch  ( auth . type )  { 
209339    case  "apiKey" : { 
340+       if  ( ! auth . result . ok )  { 
341+         throw  json ( {  error : auth . result . error  } ,  {  status : 401  } ) ; 
342+       } 
343+ 
210344      if  ( auth . result . environment . project . externalRef  !==  projectRef )  { 
211345        throw  json ( 
212346          { 
@@ -337,6 +471,14 @@ export async function validateJWTTokenAndRenew<T extends z.ZodTypeAny>(
337471        return ; 
338472      } 
339473
474+       if  ( ! authenticatedEnv . ok )  { 
475+         logger . error ( "Failed to renew JWT token, invalid API key" ,  { 
476+           error : error . message , 
477+         } ) ; 
478+ 
479+         return ; 
480+       } 
481+ 
340482      const  payload  =  payloadSchema . safeParse ( error . payload ) ; 
341483
342484      if  ( ! payload . success )  { 
0 commit comments