@@ -17,6 +17,8 @@ import {
1717 InvalidDataError ,
1818 OAuthProviderFailureError ,
1919 EdgeDBAuthError ,
20+ type RegistrationResponseJSON ,
21+ type AuthenticationResponseJSON ,
2022} from "@edgedb/auth-core" ;
2123import {
2224 ClientAuth ,
@@ -282,6 +284,45 @@ export class ServerRequestAuth extends ClientAuth {
282284 this . setVerifierCookie ( verifier ) ;
283285 }
284286
287+ async webAuthnSignUp ( data : {
288+ email : string ;
289+ credentials : RegistrationResponseJSON ;
290+ verify_url : string ;
291+ user_handle : string ;
292+ } ) : Promise < { tokenData : TokenData | null } > {
293+ const {
294+ email,
295+ credentials,
296+ verify_url : verifyUrl ,
297+ user_handle : userHandle ,
298+ } = data ;
299+
300+ const result = await (
301+ await this . core
302+ ) . signupWithWebAuthn ( email , credentials , verifyUrl , userHandle ) ;
303+
304+ this . setVerifierCookie ( result . verifier ) ;
305+ if ( result . status === "complete" ) {
306+ this . setAuthTokenCookie ( result . tokenData . auth_token ) ;
307+ return { tokenData : result . tokenData } ;
308+ }
309+
310+ return { tokenData : null } ;
311+ }
312+
313+ async webAuthnSignIn ( data : {
314+ email : string ;
315+ assertion : AuthenticationResponseJSON ;
316+ } ) : Promise < { tokenData : TokenData | null } > {
317+ const { email, assertion } = data ;
318+ const tokenData = await (
319+ await this . core
320+ ) . signinWithWebAuthn ( email , assertion ) ;
321+
322+ this . setAuthTokenCookie ( tokenData . auth_token ) ;
323+ return { tokenData } ;
324+ }
325+
285326 async signout ( ) : Promise < void > {
286327 this . deleteAuthTokenCookie ( ) ;
287328 }
@@ -653,6 +694,66 @@ async function handleAuthRoutes(
653694 } ) ;
654695 }
655696
697+ case "webauthn/signup/options" : {
698+ const email = searchParams . get ( "email" ) ;
699+ if ( ! email ) {
700+ throw new InvalidDataError ( "email missing" ) ;
701+ }
702+ return redirect ( 302 , ( await core ) . getWebAuthnSignupOptionsUrl ( email ) ) ;
703+ }
704+
705+ case "webauthn/signin/options" : {
706+ const email = searchParams . get ( "email" ) ;
707+ if ( ! email ) {
708+ throw new InvalidDataError ( "email missing" ) ;
709+ }
710+ return redirect ( 302 , ( await core ) . getWebAuthnSigninOptionsUrl ( email ) ) ;
711+ }
712+
713+ case "webauthn/verify" : {
714+ if ( ! onEmailVerify ) {
715+ throw new ConfigurationError (
716+ `'onEmailVerify' auth route handler not configured`
717+ ) ;
718+ }
719+
720+ const verificationToken = searchParams . get ( "verification_token" ) ;
721+ if ( ! verificationToken ) {
722+ return onEmailVerify ( {
723+ error : new InvalidDataError ( "verification_token missing" ) ,
724+ } ) ;
725+ }
726+ const verifier = cookies . get ( config . pkceVerifierCookieName ) ;
727+ if ( ! verifier ) {
728+ return onEmailVerify ( {
729+ error : new PKCEError ( "no pkce verifier cookie found" ) ,
730+ verificationToken,
731+ } ) ;
732+ }
733+ let tokenData : TokenData ;
734+ try {
735+ tokenData = await (
736+ await core
737+ ) . verifyWebAuthnSignup ( verificationToken , verifier ) ;
738+ } catch ( err ) {
739+ return onEmailVerify ( {
740+ error : err instanceof Error ? err : new Error ( String ( err ) ) ,
741+ verificationToken,
742+ } ) ;
743+ }
744+
745+ cookies . set ( config . authCookieName , tokenData . auth_token , {
746+ httpOnly : true ,
747+ sameSite : "strict" ,
748+ path : "/" ,
749+ } ) ;
750+
751+ return onEmailVerify ( {
752+ error : null ,
753+ tokenData,
754+ } ) ;
755+ }
756+
656757 case "signout" : {
657758 if ( ! onSignout ) {
658759 throw new ConfigurationError (
0 commit comments