Skip to content

Instantly share code, notes, and snippets.

@Tuizi
Last active July 11, 2024 07:25
Show Gist options
  • Save Tuizi/c652e723360db531cc3ebe824042f4b4 to your computer and use it in GitHub Desktop.
Save Tuizi/c652e723360db531cc3ebe824042f4b4 to your computer and use it in GitHub Desktop.
Auth0 Token + React Router Loader

Use Auth0 JWT Tokens in React Router Dom Loaders

This README outlines the implementation details of passing JWT tokens in a React application using React Router. This is crucial for managing access controls and secure communication between the client and server.

Overview

The application utilizes React Router for navigation and Auth0 for authentication. The main focus is on how to effectively pass JWT tokens retrieved from Auth0 to various components and routes.

Technologies Used

  • React W/ TypeScript
  • Auth0
  • React Router
  • React Query (example)

File Structure

  • main.tsx: Entry point for application, setups up React DOM.
  • app.router.tsx: Contains routing logic and token management.
  • auth/: Directory containing authentication components and logic.
  • games/: Directory for game-related components and routing.

Key Code Snippets

Below are some key code snippets to showcase how JWT tokens are passed to routes and used in the loader function:

Storing and Retrieving the Token

const [token, setToken] = useState<string>();  // State to hold the JWT token

useEffect(() => {
  const fetchToken = async () => {
    const accessToken = await auth0.getAccessTokenSilently();

    setToken(accessToken);
  };

  fetchToken();
}, [auth0]);

Passing the Token to Routes

const authenticatedRoutes = useMemo(() => {
  if (!token) {
    return [];  // No routes if no token
  }

  return [
    featureRouter(token),  // Passing the token to a feature's router
    // Additional authenticated routes can be added here
  ];
}, [token]);

Example Loader Function Using the Token

In this hypothetical example, featureRouter might use the token as follows:

export const featureRouter = (token) => ({
  path: 'feature',
  element: <FeatureComponent />,
  loader: async () => {
    const response = await fetch('/api/data', {
      headers: { Authorization: `Bearer ${token}` }  // Use the token for API requests
    });
    return response.json();
  },
  children: [
    // Child routes can also be protected using the token
  ]
});

Explanation

  • Authentication: The application uses useAuth0 to handle user authentication via Auth0's React SDK.
  • Token Management: A JWT token is fetched and stored using React's state management. It is then passed to routes requiring authentication.
  • Route Configuration: Routes are conditionally rendered based on the presence of a valid JWT token, ensuring that secure content is only available to authenticated users.

This setup provides a robust framework for handling JWT tokens in a React application, enhancing security and ensuring that sensitive information remains protected.

import React from "react";
import ReactDOM from "react-dom/client";
import { Auth0Provider } from "@auth0/auth0-react";
import { AppRouter } from "./app.router";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Auth0Provider
domain={import.meta.env.VITE_AUTH0_DOMAIN}
clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: window.location.origin,
}}
>
<AppRouter />
</Auth0Provider>
</React.StrictMode>
);
import { useAuth0 } from "@auth0/auth0-react";
import { useEffect, useMemo, useState } from "react";
import {
createBrowserRouter,
RouterProvider,
Link,
Outlet,
} from "react-router-dom";
import Profile from "./auth/profile";
import { gamesRouter } from "./games/games.router";
export const AppRouter = () => {
const auth0 = useAuth0();
const [token, setToken] = useState<string>();
useEffect(() => {
const execute = async () => {
const accessToken = await auth0.getAccessTokenSilently();
setToken(accessToken);
};
execute();
}, [auth0]);
const authenticatedRoutes = useMemo(() => {
if (!token) {
return [];
}
return [
gamesRouter(token),
// other routes protected by authentication
];
}, [token]);
const router = createBrowserRouter([
{
path: "/",
element: (
<>
<header>
<Profile />
<Link to="games">Games</Link>
</header>
<main>
<Outlet />
</main>
</>
),
children: [...authenticatedRoutes],
},
]);
return <RouterProvider router={router} />;
};
import { RouteObject } from "react-router-dom";
import { Games } from "./games";
export const gamesRouter = (token: string) => {
return {
path: "/games",
element: <Games />,
loader: async ({ request }) => {
const resp = await fetch("https://api.sampleapis.com/switch/games", {
signal: request.signal,
headers: {
Authorization: "Bearer " + token,
},
});
return resp.json();
/**
* OR with React Query
*
* const games = await resp.json();
* queryClient.setQueryData(["games"], games);
* return games; // or `null` to avoid 2 source of data (useLoaderData + useQuery)
*/
},
} satisfies RouteObject;
};
import { useLoaderData } from "react-router-dom";
interface GameData {
id: string;
name: string;
}
export const Games: React.FC = () => {
const games = useLoaderData() as GameData[];
/**
* OR with React Query
*
* const {data: games} = useQuery<GameData[]>({queryKey: ['games']});
*/
return (
<>
<h2>Games</h2>
<ul>
{games.map((game) => (
<li key={game.id}>{game.name}</li>
))}
</ul>
</>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment