User Authentication & Authorization

Implement secure user authentication and authorization in your application.

Overview

ZapStart comes with a complete authentication and authorization system built-in. This tutorial will guide you through using the pre-built components and functions to:

  • Authenticate users through Google OAuth
  • Protect routes and API endpoints
  • Check user subscription status and access levels
  • Create conditional UI based on auth state

Pre-built Authentication

ZapStart handles all the complex authentication logic for you, including OAuth flows, JWT token management, and refresh token rotation.

Authentication

Authentication in ZapStart uses Google OAuth with JWT tokens for persistence. The login flow is already implemented and ready to use.

Login Implementation

The login button component will redirect the user to the Google login page or to the dashboard if the user is already logged in (this is the button you should be using whenver requiring the user to login and it will redirect user to the proper page).

// Pre-built login button component - just import and use
import { ButtonLogin } from "@/components/ButtonLogin";

// In your component
return (
  <div>
    <ButtonLogin />  {/* Automatically redirects to Google login */}
  </div>
);

In the login page, Sign in with Google button will handle the OAuth flow and the user will then be redirected to the dashboard:

Login Page

Logout Implementation

Implementing logout functionality:

Use the logout button component to logout the user and redirect them to the login page, logout button should be located in dashboard page:

import { LogoutButton } from "@/components/LogoutButton";

function DashboardHeader() {

  return (
  <div>
    <LogoutButton />
  </div>
  );
}

Authentication Context [Frontend]

ZapStart provides an AuthContext that gives you access to the current user's authentication state, you can access the user object within any component in the app, just import the useAuth hook:

import { useAuth } from "@/context/AuthContext";

function MyComponent() {
  const { user, loading } = useAuth();
  
  if (loading) return <p>Loading...</p>;
  
  return (
    <div>
      {user ? (
        <p>Welcome, {user.name}!</p>
      ) : (
        <p>Please log in</p>
      )}
    </div>
  );
}

Authorization [Backend]

Authorization determines what a user can access after they've been authenticated.

Protecting API Routes

Secure your backend API routes with the authenticateJWT middleware backend/src/middleware/auth.js, authenticateJWT will make sure the user is authenticated before accessing the protected routes, otherwise it will return a 401 Unauthorized error, and that may trigger need for new access token (so it will require the refresh token from the client/frontend to gain new access token) or redirect to login page, don't worry about this boring stuff, this is automatically handled for you by default.

// In your routes file
const express = require('express');
const router = express.Router();
const { authenticateJWT } = require('../middleware/auth');
const yourController = require('../controllers/yourController');

// Public route - no auth required
router.get('/public', yourController.publicHandler);

// Protected route - requires valid JWT
router.get('/protected', authenticateJWT, yourController.protectedHandler);

Protected routes could be like users personal data, logout backend function or any data that should be protected from unauthorized access. All these are handled for you by default.

In the Payment tutorial you will learn how to protect routes based on the user's plan. e.g giving access to Pro Features only to users with a Pro Plan.

Best Practices

  • Always use the authenticateJWT middleware for any route that should be protected
  • Use the pre-built components (ButtonLogin, LogoutButton) for consistent auth flows
  • Add loading states when checking authentication to improve user experience
  • Keep authentication logic in higher-level components frontend/context/AuthContext.js and pass down user information as props, using useAuth hook

Security First

Always implement both frontend and backend checks for protected routes. Frontend checks improve the user experience, but backend validation is essential for security.