Cover photo

React-Query in Next.js for JWT Authentication: Because We All Need More Authentication Fluff

Ciao, fellow developers. Today, we're going to explore the captivating world of React-Query in Next.js for JWT authentication. Grab your code spaghetti, and let's saunter through the Italian-style journey of web authentication because we can never have enough of that! 🍝👨‍💻

Prerequisites

  1. You better know React.js and Next.js, or Mama Mia, we got problems!

  2. Node.js and npm installed, or you'll have a bad time.

Step 1: Project Setup

Let's start by creating a new Next.js project. Fire up your terminal and run this command:

npx create-next-app your-project-name

Now, navigate to your project's cozy corner:

cd your-project-name

Step 2: Installing React-Query

It's time to import React-Query into our project. Execute this command to make it happen:

npm install react-query

Step 3: Configuring React-Query

Let's configure React-Query like we're setting up a fancy Italian feast. Create a react-query.js file in your project's root directory. This file is where the magic happens:

// react-query.js
import { QueryClient, QueryClientProvider } from 'react-query';

// Whip up a fresh QueryClient instance
const queryClient = new QueryClient();

// Export the QueryClient and QueryClientProvider, because why not?
export { queryClient, QueryClientProvider };

Step 4: Setting Up JWT Authentication

For JWT authentication, we'll create functions to handle login, logout, and checking the authentication status. Behold the majestic auth.js file, residing in a "utils" folder:

// utils/auth.js
import { useMutation, useQuery } from 'react-query';

// Pretend user data, just like nonna's secret recipe
const mockUser = {
  id: 1,
  username: 'john_doe',
};

// Simulate a login API request
const login = async (credentials) => {
  // Replace this with your real login logic, if you have one
  if (credentials.username === 'john_doe' && credentials.password === 'password') {
    return mockUser;
  }
  throw new Error('Invalid credentials');
};

// Simulate a logout API request
const logout = async () => {
  // Replace this with your logout logic, if you even have one
  return true;
};

// Fetch user data
const fetchUser = async () => {
  // Replace this with your actual user data retrieval logic
  return mockUser;
};

// Export your authentication functions
export const useLogin = () => useMutation(login);
export const useLogout = () => useMutation(logout);
export const useAuth = () => useQuery('user', fetchUser);

Step 5: Integrating Authentication into Your Components

Now, let's serve up some authentication in your React components. Say you've got a Login component and a Profile component. Here's how to use React-Query to manage the authentication show:

// pages/login.js
import { useLogin } from '../utils/auth';

function Login() {
  const [credentials, setCredentials] = useState({ username: '', password: '' });
  const loginMutation = useLogin();

  const handleLogin = () => {
    loginMutation.mutateAsync(credentials);
  };

  return (
    <div>
      <h2>Login</h2>
      <input
        type="text"
        placeholder="Username"
        onChange={(e) => setCredentials({ ...credentials, username: e.target.value })}
      />
      <input
        type="password"
        placeholder="Password"
        onChange={(e) => setCredentials({ ...credentials, password: e.target.value })}
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  );
}

export default Login;
// pages/profile.js
import { useAuth, useLogout } from '../utils/auth';

function Profile() {
  const { data: user, isLoading, isError } = useAuth();
  const logoutMutation = useLogout();

  const handleLogout = () => {
    logoutMutation.mutateAsync();
  };

  if (isLoading) {
    return <p>Loading...</p>;
  }

  if (isError) {
    return <p>Error fetching user data</p>;
  }

  return (
    <div>
      <h2>Welcome, {user.username}!</h2>
      <button onClick={handleLogout}>Logout</button>
    </div>
  );
}

export default Profile;

Step 6: Protecting Routes

To protect routes that need authentication, you can use Next.js's getServerSideProps or getStaticProps. Let's protect the Profile page with some spicy logic:

// pages/profile.js
import { useAuth, useLogout } from '../utils/auth';
import { useRouter } from 'next/router';

function Profile() {
  const { data: user, isLoading, isError } = useAuth();
  const logoutMutation = useLogout();
  const router = useRouter();

  const handleLogout = async () => {
    await logoutMutation.mutateAsync();
    router.push('/login');
  };

  if (isLoading) {
    return <p>Loading...</p>;
  }

  if (isError) {
    return <p>Error fetching user data</p>;
  }

  return (
    <div>
      <h2>Welcome, {user.username}!</h2>
      <button onClick={handleLogout}>Logout</button>
    </div>
  );
}

export async function getServerSideProps({ req, res }) {
  // Check if the user is authenticated using your authentication logic
  const isAuthenticated = /* Your authentication logic here */;

  if (!isAuthenticated) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    };
  }

  return {
    props: {},
  };
}

export default Profile;

Step 7: Wrapping Your App with QueryClientProvider

To make React-Query work its magic across your Next.js app, wrap it with the QueryClientProvider in your _app.js file:

// pages/_app.js
import { QueryClientProvider } from 'react-query';
// Import your configured QueryClient
import { queryClient } from '../react-query';

import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />
    </QueryClientProvider>
  );
}

export default MyApp;

Step 8: Running Your Next.js Application

Now, my dear friends, it's time to fire up your Next.js development server:

npm run dev

Open your browser and visit http://localhost:3000. Voilà! Your web app with React-Query for JWT authentication is good to go!

Conclusion

So there you have it, an Italian-flavored journey through React-Query in Next.js for JWT authentication. Customize, sprinkle