@@ -20,6 +20,8 @@ import { isPublicJWT, validatePublicJwtKey } from "./realtime/jwtAuth.server";
20
20
21
21
const ClaimsSchema = z . object ( {
22
22
scopes : z . array ( z . string ( ) ) . optional ( ) ,
23
+ // One-time use token
24
+ otu : z . boolean ( ) . optional ( ) ,
23
25
} ) ;
24
26
25
27
type Optional < T , K extends keyof T > = Prettify < Omit < T , K > & Partial < Pick < T , K > > > ;
@@ -39,6 +41,7 @@ export type ApiAuthenticationResultSuccess = {
39
41
type : "PUBLIC" | "PRIVATE" | "PUBLIC_JWT" ;
40
42
environment : AuthenticatedEnvironment ;
41
43
scopes ?: string [ ] ;
44
+ oneTimeUse ?: boolean ;
42
45
} ;
43
46
44
47
export type ApiAuthenticationResultFailure = {
@@ -146,6 +149,7 @@ export async function authenticateApiKey(
146
149
...result ,
147
150
environment : validationResults . environment ,
148
151
scopes : parsedClaims . success ? parsedClaims . data . scopes : [ ] ,
152
+ oneTimeUse : parsedClaims . success ? parsedClaims . data . otu : false ,
149
153
} ;
150
154
}
151
155
}
@@ -227,6 +231,7 @@ export async function authenticateApiKeyWithFailure(
227
231
...result ,
228
232
environment : validationResults . environment ,
229
233
scopes : parsedClaims . success ? parsedClaims . data . scopes : [ ] ,
234
+ oneTimeUse : parsedClaims . success ? parsedClaims . data . otu : false ,
230
235
} ;
231
236
}
232
237
}
@@ -531,3 +536,20 @@ function calculateJWTExpiration() {
531
536
532
537
return ( Date . now ( ) + DEFAULT_JWT_EXPIRATION_IN_MS ) / 1000 ;
533
538
}
539
+
540
+ export async function getOneTimeUseToken (
541
+ auth : ApiAuthenticationResultSuccess
542
+ ) : Promise < string | undefined > {
543
+ if ( auth . type !== "PUBLIC_JWT" ) {
544
+ return ;
545
+ }
546
+
547
+ if ( ! auth . oneTimeUse ) {
548
+ return ;
549
+ }
550
+
551
+ // Hash the API key to make it unique
552
+ const hash = await crypto . subtle . digest ( "SHA-256" , new TextEncoder ( ) . encode ( auth . apiKey ) ) ;
553
+
554
+ return Buffer . from ( hash ) . toString ( "hex" ) ;
555
+ }
0 commit comments