Hands-on Lab: Full-Stack Integration
It’s time to bring everything together! In this lab, you will connect your React “Tasks” page to your Hono backend and implement a full authentication flow.
Objective
Section titled “Objective”By the end of this exercise, you will have:
- A working “Tasks” page that fetches real data from your database.
- A working “Create Task” form that adds data to your database.
- A fully functional Login and Register system.
- Protected routes that redirect unauthenticated users.
Prerequisites
Section titled “Prerequisites”- You have completed the previous modules.
- Your Hono backend is running (
npm run devinworker/). - Your React frontend is running (
npm run devinreact-app/).
Part 1: Connect the Tasks Page
Section titled “Part 1: Connect the Tasks Page”Your first task is to replace the mock data in your React app with real data from the API.
-
Configure CORS: In your Hono worker (
src/worker/index.ts), add the CORS middleware to allow requests fromhttp://localhost:5173. -
Create the Query Hook: Create
src/react-app/hooks/use-tasks-query.ts. UseuseQueryto fetch from/api/tasks. -
Update the Component: Open
src/react-app/routes/_protected/dashboard.tsx(or wherever your task list is). Replace the static array with the data from your new hook. -
Create the Mutation Hook: Create
src/react-app/hooks/use-create-task-mutation.ts. UseuseMutationto POST to/api/tasks. Don’t forget to invalidate thetasksquery key on success! -
Connect the Form: Update your
CreateTaskFormcomponent to use the mutation hook.
💡 Hint: CORS Configuration
import { cors } from "hono/cors";
app.use( "/api/*", cors({ origin: "http://localhost:5173", credentials: true, // Important for auth later! allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowHeaders: ["Content-Type", "Authorization"], }));Part 2: Implement Authentication
Section titled “Part 2: Implement Authentication”Now, let’s secure the application.
-
Backend Setup: In
src/worker/lib/auth.ts, configurebetter-authwith the Drizzle adapter. -
Auth Routes: In
src/worker/index.ts, mount the auth handler at/api/auth/**. -
Frontend Client: Create
src/react-app/lib/auth-client.tsusingcreateAuthClient. -
Login Page: Create or update
src/react-app/routes/_auth/login.tsx. UsesignIn.emailto log the user in. -
Register Page: Create or update
src/react-app/routes/_auth/sign-up.tsx. UsesignUp.emailto register a new user.
💡 Hint: Frontend Auth Client
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({ baseURL: "http://localhost:8787/api/auth",});Part 3: Protect the Dashboard
Section titled “Part 3: Protect the Dashboard”Finally, ensure that only logged-in users can see the tasks.
-
Create Layout: Create
src/react-app/routes/_protected.tsx. -
Add Guard: Use
beforeLoadto checkauthClient.getSession(). Redirect to/loginif no session exists. -
Move Routes: Move your
dashboard.tsxroute file inside the_protecteddirectory (or rename it to_protected/dashboard.tsxif using flat files). -
Test It: Try accessing
/dashboardin an incognito window. You should be bounced to/login.
Verification
Section titled “Verification”- Can you see tasks from the database on the dashboard?
- Can you create a new task and see it appear instantly?
- Can you register a new account?
- Can you log in and log out?
- Does the app redirect you to login if you try to access the dashboard while logged out?
Congratulations! You have built a fully integrated, secure full-stack application. This is a huge achievement! 🚀