@@ -119,6 +119,57 @@ export const logoutBetterAuth = async (
119119 }
120120} ;
121121
122+ const isOAuthCallbackPath = ( url : string ) : boolean =>
123+ / \/ a u t h \/ c a l l b a c k \/ / . test ( url ) ;
124+
125+ const rewriteOAuthErrorRedirect = (
126+ request : FastifyRequest ,
127+ response : Response ,
128+ ) : string | undefined => {
129+ if ( ! isOAuthCallbackPath ( request . url ) ) {
130+ return undefined ;
131+ }
132+
133+ if ( response . status < 300 || response . status >= 400 ) {
134+ return undefined ;
135+ }
136+
137+ const location = response . headers . get ( 'location' ) ;
138+ if ( ! location ) {
139+ return undefined ;
140+ }
141+
142+ const webappCallback = `${ process . env . COMMENTS_PREFIX } /callback` ;
143+ if ( ! webappCallback ) {
144+ return undefined ;
145+ }
146+
147+ if ( location . startsWith ( webappCallback ) ) {
148+ return undefined ;
149+ }
150+
151+ let redirectUrl : URL ;
152+ try {
153+ redirectUrl = new URL ( location , `${ request . protocol } ://${ request . host } ` ) ;
154+ } catch {
155+ return undefined ;
156+ }
157+
158+ const hasError =
159+ redirectUrl . searchParams . has ( 'error' ) ||
160+ redirectUrl . searchParams . get ( 'state' ) === 'state_not_found' ;
161+ if ( ! hasError ) {
162+ return undefined ;
163+ }
164+
165+ const callbackUrl = new URL ( webappCallback ) ;
166+ redirectUrl . searchParams . forEach ( ( value , key ) => {
167+ callbackUrl . searchParams . set ( key , value ) ;
168+ } ) ;
169+
170+ return callbackUrl . toString ( ) ;
171+ } ;
172+
122173const betterAuthRoute = async ( fastify : FastifyInstance ) : Promise < void > => {
123174 // Apple sends OAuth callbacks as application/x-www-form-urlencoded POSTs.
124175 // Fastify does not parse this content type by default, so collect the raw
@@ -142,6 +193,18 @@ const betterAuthRoute = async (fastify: FastifyInstance): Promise<void> => {
142193 reply,
143194 body,
144195 } ) ;
196+
197+ const rewrittenUrl = rewriteOAuthErrorRedirect ( request , response ) ;
198+ if ( rewrittenUrl ) {
199+ request . log . warn (
200+ { originalLocation : response . headers . get ( 'location' ) } ,
201+ 'OAuth callback error redirect rewritten to webapp' ,
202+ ) ;
203+ reply . header ( 'location' , rewrittenUrl ) ;
204+ reply . status ( 302 ) ;
205+ return reply . send ( ) ;
206+ }
207+
145208 return sendBetterAuthResponse ( reply , response ) ;
146209 } catch ( error ) {
147210 return sendBetterAuthError (
0 commit comments