Redirect is not working properly in SSR pages in Gatsby App

Hello,

App name: https://elegant-clafoutis-c14441.netlify.app

I am creating a gatsby app and created an SSR Page that requires the auth cookie to present in the browser. If the user has not authenticated, the SSR page should redirect the user to login page (CSR).

The problem is that it redirects to a blank page. The login page is client-side rendered, so I am redirecting from a server-side rendered page to a client-side rendered page.

I am using navigate from @reach/router to redirect the user. It redirects to the /login route but it’s a blank page. I’ve tried navigate form gatsby package, it works in development without issues but not in production. In production, on netlify, the admin (SSR) page throw 500 error.

Here is the SSR page I created including the redirect block -

// this is the admin page (created server-side), which is the page that will be shown when the user is logged in
import React from "react"
import cookie from "cookie"
import MainLayout from "../../components/admin/layouts/main"
import { navigate } from "@reach/router"

const Admin = ({ serverData }) => {
    // check if cookie is not empty
    if (Object.keys(serverData.data).length === 0) {
        // redirect to login page
        navigate("/login/")

        return null
    }

    // check if user is authneticated

    // return the admin page
    return (
        <MainLayout>
            <h1>Admin Page</h1>
        </MainLayout>
    )
}

export default Admin

// getServerData to make this server-rendered page
export async function getServerData(context) {
    // create try catch block
    try {
        const { headers, method, url, query, params } = context

        // parse cookies from headers
        const cookies = cookie.parse(headers.get("cookie") || "")

        return {
            status: 200,
            props: {
                data: cookies,
            },
            headers: {},
        }
    } catch {
        return {
            status: 500,
            props: {
                data: {},
            },
            headers: {},
        }
    }
}

export const Head = () => <title>Admin page</title>

Thanks!

I have resolved it. Instead of redirecting directly, I used useState and useEffect hooks to do the job.

Also, use navigate from the gatsby package, instead of from @reach/router.

Here is the revised code for future visitors -

// this is the admin page (created server-side), which is the page that will be shown when the user is logged in
import React, { useEffect, useState } from "react"
import cookie from "cookie"
import MainLayout from "../../components/admin/layouts/main"
import { navigate, Link } from "gatsby"

const Admin = ({ serverData }) => {
    // redirect to login page
    const [authenticated, setAuthenticated] = useState(false)

    useEffect(() => {
        if (Object.keys(serverData.data).length === 0) {
            navigate("/login/")
        } else {
            setAuthenticated(true)
        }
    }, [serverData.data])

    if (!authenticated) {
        // Don't render the admin content for non-logged-in users
        return null
    }

    // check if user is authneticated

    // return the admin page
    return (
        <MainLayout>
            <h1>Admin Page</h1>
        </MainLayout>
    )
}

export default Admin

// getServerData to make this server-rendered page
export async function getServerData(context) {
    // create try catch block
    const { headers, method, url, query, params } = context

    // parse cookies from headers
    const cookies = cookie.parse(headers.get("cookie") || "")

    return {
        status: 200,
        props: {
            data: cookies,
        },
        headers: {},
    }
}

export const Head = () => <title>Admin page</title>

Hi Sandy,

Thanks a bunch for following up and documenting this solution!