sergiodxa / remix-auth-oauth2

A OAuth2Strategy for Remix Auth
https://sergiodxa.github.io/remix-auth-oauth2/
MIT License
150 stars 56 forks source link

Redirecting the user to the callback URL results in SyntaxError: Unexpected end of JSON input #78

Closed argus-ralph closed 9 months ago

argus-ralph commented 9 months ago

Currently I call the authenticator.authenticate function with the remix-auth-facebook strategy whenever someone posts to the following route with this action, where dataSource corresponds to Facebook:

export async function action({ request, params }: DataFunctionArgs) {
    const dataSourceName = DataSourceNameSchema.parse(params['data_source'])
    try {
        return await dataSourceAuthenticator.authenticate(dataSourceName, request)
    } catch (error: unknown) {
        console.log(error)
        if (error instanceof Response) {
            console.log(await error.json())
            const formData = await request.formData()
            const rawRedirectTo = formData.get('redirectTo')
            const redirectTo =
                typeof rawRedirectTo === 'string'
                    ? rawRedirectTo
                    : getReferrerRoute(request)
            const redirectToCookie = getRedirectCookieHeader(redirectTo)
            if (redirectToCookie) {
                error.headers.append('set-cookie', redirectToCookie)
            }
        }
    }
}

And the authenticate function stops working whenever remix-auth-oauth2 tries to redirect the user to the provided callback URL

        if (url.pathname !== callbackURL.pathname) {
            debug('Redirecting to callback URL')
            let state = this.generateState()
            debug('State', state)
            session.set(this.sessionStateKey, state)
            let url = this.getAuthorizationURL(request, state).toString()
            debug('AuthorizationUrl', url)

            throw redirect(this.getAuthorizationURL(request, state).toString(), {
                headers: {
                    'Set-Cookie': await sessionStorage.commitSession(session),
                },
            })
        }

The logged error is equal to:

SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at Response.json (/home/ralph/ventures/argus/node_modules/@remix-run/web-fetch/src/body.js:162:15)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at action10 (file:///home/ralph/ventures/argus/build/index.js?update=1701289190908:5860:19)
    at /home/ralph/ventures/argus/node_modules/@sentry/remix/cjs/utils/instrumentServer.js:2:3500
    at Object.callRouteActionRR (/home/ralph/ventures/argus/node_modules/@remix-run/server-runtime/dist/data.js:11:190)
    at callLoaderOrAction (/home/ralph/ventures/argus/node_modules/@remix-run/router/dist/router.cjs.js:11:77600)
    at submit (/home/ralph/ventures/argus/node_modules/@remix-run/router/dist/router.cjs.js:11:64446)
    at queryImpl (/home/ralph/ventures/argus/node_modules/@remix-run/router/dist/router.cjs.js:11:63629)
    at Object.queryRoute (/home/ralph/ventures/argus/node_modules/@remix-run/router/dist/router.cjs.js:11:62814)
POST /auth/data-source/facebook?_data=routes/_auth+/auth.data-source.$data_source 500 - - 27.790 ms

I have no idea why it is giving me this error. I found a solution where I return the redirect as follows:

return redirect(this.getAuthorizationURL(request, state).toString(), {
                headers: {
                    'Set-Cookie': await sessionStorage.commitSession(session),
                },
            }) as any as Promise<User>

But this is ofcourse not ideal. Do you have any suggestions on what I can do here or is anyone else experiencing this?

argus-ralph commented 9 months ago

Because you are throwing the redirect, you catch it also in the try catch black so after checking the error you should throw if what you caught is actually a redirect

export async function action({ request, params }: DataFunctionArgs) {
    const dataSourceName = DataSourceNameSchema.parse(params['data_source'])
    try {
        return await dataSourceAuthenticator.authenticate(dataSourceName, request)
    } catch (error: unknown) {
        console.log(error)
        if (error instanceof Response) {
            console.log(await error.json())
            const formData = await request.formData()
            const rawRedirectTo = formData.get('redirectTo')
            const redirectTo =
                typeof rawRedirectTo === 'string'
                    ? rawRedirectTo
                    : getReferrerRoute(request)
            const redirectToCookie = getRedirectCookieHeader(redirectTo)
            if (redirectToCookie) {
                error.headers.append('set-cookie', redirectToCookie)
            }
        }
        throw error

    }
}