0

I am using Remix, along with Remix-Auth and using the Twitch API/OAuth, which requires that I check in with their /validate endpoint every hour docs. I had someone recommend that I use a resource route and POST to that if the validation endpoint returned a status of 401, however, I need as I stated before the request needs to be sent every hour I figured maybe I could use something like React-Query to POST to the resource route every hour.

Just pointing out that I use createCookieSessionStorage with Remix Auth to create the session

Problem

I haven't been able to achieve the actual session being destroyed and a user being re-routed to the login page, I have left what actual code I have currently any help or suggestions to actually achieve the session being destroyed and be re-routed to the login page if the validation fails would be greatly appreciated.

// React Query client side, checks if the users token is still valid
  const { error, data } = useQuery("TV-Revalidate", () =>
    fetch("https://id.twitch.tv/oauth2/validate", {
      headers: {
        Authorization: `Bearer ${user?.token}`,
      },
    }).then((res) => res.json())
  );

The above React Query returns this Screenshot of returned data

// My attempt at the resource route
// ~routes/auth/destroy.server.ts
import { ActionFunction, redirect } from "@remix-run/node";
import { destroySession, getSession } from "~/services/session.server";

export const action: ActionFunction = async ({request}) => {
    const session = await getSession(request.headers.get("cookie"))
    return redirect("/login", {
        headers: {
            "Set-Cookie": await destroySession(session)
        }
    })
}
// Second attempt at resource route
// ~routes/auth/destroy.server.ts
import { ActionFunction, redirect } from "@remix-run/node";
import { destroySession, getSession } from "~/services/session.server";

export const action: ActionFunction = async ({request}) => {
    const session = await getSession(request.headers.get("cookie"))
    return destroySession(session)
}

I attempted using an if statement to POST to the resource route or else render the page, however, this definitely won't work as React errors out because functions aren't valid as a child and page is blank.

//index.tsx
export default function Index() {
  const { user, bits, vali } = useLoaderData();

  console.log("loader", vali);

  const { error, data } = useQuery("TV-Revalidate", () =>
    fetch("https://id.twitch.tv/oauth2/validate", {
      headers: {
        Authorization: `Bearer ${user?.token}`,
      },
    }).then((res) => res.json())
  );

  if (data?.status === 401)
    return async () => {
      await fetch("~/services/destroy.server", { method: "POST" });
    };
  else
    return ( ... );}
MatDoak
  • 132
  • 5
  • 17

1 Answers1

0

You could use Remix' useFetcher hook.

https://remix.run/docs/en/v1/api/remix#usefetcher

// Resource route
// routes/api/validate
export const loader: LoaderFunction = async ({ request }) => {
    const session = await getSession(request);
    try {
        const { data } = await fetch("https://id.twitch.tv/oauth2/validate", {
            headers: {
                Authorization: `Bearer ${session.get("token")}`
            }
        });
        return json({
            data
        }, {
            headers: {
                "Set-Cookie": await commitSession(session),
            }
        });
        
    } catch(error) {
        return redirect("/login", {
            headers: {
                "Set-Cookie": await destroySession(session)
            }
        });
    }
}

And then in your route component something like this:

    const fetcher = useFetcher();
    
    useEffect(() => {
        if (fetcher.type === 'init') {
            fetcher.load('/api/validate');
        }
    }, [fetcher]);
    
    useEffect(() => {
        if(fetcher.data?.someValue {
            const timeout = setTimeout(() => fetcher.load('/api/validate'), 1 * 60 * 60 * 1000);
            return () => clearTimeout(timeout);
        }
    },[fetcher.data]);