How to use Access Tokens to implement Protected Routes in React

The token for my react application is stored in the AuthContext Provider and whenever the user is logged, the token is set using the setToken() function.

AuthContext.js

import { useContext, useState, createContext, useMemo } from "react";
import {createAxiosInstance} from '../services/axiosInstance';
import { useNavigate } from "react-router-dom";

const AuthContext = createContext();

const AuthProvider = ({children}) => {
    const [token, setToken] = useState(null);

    // creates a new instance of axios Instance when the token is changed
    const axiosInstance = useMemo(() => createAxiosInstance(token), [token]);

    // create the login and signup functions here
    const login = (email, password) => {
        const data = {"email": email, "password": password};
        console.log("Logging the user in");
        const response = axiosInstance.post('/auth', data);

        return new Promise((resolve, reject)=>{
            response.then((responseData) => {
                const {accessToken, message} = responseData.data;
                setToken(accessToken);
                return resolve(message);
            })
            .catch((err)=>{
                return reject("Wrong email or password");
            })
        })
    }

    return (
        <AuthContext.Provider value={{token,setToken, axiosInstance, login}}>
            {children}
        </AuthContext.Provider>
    );
}

const useAuth = () => {
    const context = useContext(AuthContext);
    if(context === undefined){
        throw new Error("The Context must be used under the AuthContextProvider");
    }
    return context;
}

export {AuthProvider as default, useAuth}

Inorder to implement protected routes in my application, I wrapped this component around all the routes that I wanted to be protected

import { jwtDecode } from "jwt-decode"
import { useAuth } from "../contexts/AuthProvider"
import { Navigate, Outlet } from "react-router-dom";

const ProtectedRoutes = ({ children }) => {
    const { token, setToken, axiosInstance } = useAuth();

    // if there is no token, send the user to the authentication route
    if (!token) {
        return <Navigate to='/users/authenticate' />
    }

    try {
        // get the expiry time from the token
        const { exp } = jwtDecode(token);
        const expired = (Date.now() >= exp * 1000);

        
        if (expired) {
            axiosInstance.post('/auth/refresh')     // if the token has expired, try to get a new token
                .then((response) => {
                    const { accessToken } = response.data;
                    setToken(accessToken)
                    return <Outlet />
                })
                .catch((err) => {   // if the user has no token stored in their cookies, then send them to login page
                    return <Navigate to="/users/authenticate" />
                })
        }
        else{
            return <Outlet />   // if the token has not expired, continue
        }
    }
    catch (err) {
        return <Navigate to='/users/authenticate' />
    }
}

export default ProtectedRoutes;

But whenever I refresh the page, the token is set to null and protected routes logs me out.
How can I save the access Token other than storing it in localStorage or sessionStorage as I heard that those methods are not safe to attacks.