Integrate the Frontend
Set up your React single-page app frontend with an Auth Context to initialize the session.
If you don't have a frontend already, create a React project using any approach from the official Starting a new project page.
For the purpose of this guide, we are assuming you are using vanilla React.
With auth and session management now implemented in your Express server, let's set up an Auth Context and Provider to manage authentication state and protect your routes.
React Frontend SDK Coming Soon
We're working on adding a React frontend Wristband SDK for encapsulating most of this logic for you. Stay tuned!
Add Helper Functions
You can add these helper functions in your React project to manage authentication redirects and error checking (e.g. src/utils/helpers.ts
).
redirectToLogin()
redirectToLogin()
This redirects users to your Express Login endpoint, with an option to save the current URL for automatic return after authentication.
// helpers.ts
export function redirectToLogin(loginUrl?: string, returnUrl?: string) {
if (!!window) {
if (returnUrl) {
const queryParams = new URLSearchParams({ return_url: encodeURI(returnUrl) }).toString();
window.location.href = `${}/api/auth/login?${queryParams}`;
} else {
window.location.href = `${window.location.origin}/api/auth/login`;
}
}
}
redirectToLogout()
redirectToLogout()
This redirects user to your Express Logout endpoint.
// helpers.ts
export function redirectToLogout(logoutUrl?: string) {
if (!!window) {
const location = logoutUrl ?? window.location.origin;
window.location.href = `${location}/api/auth/logout`;
}
}
isUnauthorized()
isUnauthorized()
This checks if an Axios error was caused by an unauthorized request (HTTP 401), typically due to an expired session or access token.
You can use other AJAX clients besides Axios, but you'll need to change error validation accordingly.
// helpers.ts
import { AxiosError } from 'axios';
// Checks is the response from an API call to your Express server returned a 401 satus.
export function isUnauthorized(error: AxiosError) {
if (!error) {
return false;
}
if (error instanceof AxiosError) {
return error.response?.status === 401;
}
return false;
}
Create an Auth Context
Create a React Context like the following for loading and managing initial authentication state (e.g., src/context/auth-context.tsx
):
import React, { createContext, useContext, useEffect, useState } from 'react';
import { isUnauthorized, redirectToLogin, redirectToLogout } from "@/util/helpers";
// User data in your context can be shaped to fit your you needs.
// This is just a small example of what is possible.
type User = {
email: string
};
type AuthContextProps = {
isAuthenticated?: boolean;
isLoading?: boolean;
setUser: (user: User) => void;
user: User;
};
const AuthContext = createContext<AuthContextProps>({
isAuthenticated: false,
isLoading: false,
setUser: () => {},
user: { email: '' },
});
const AuthProvider = ({ children: React.ReactNode }) => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [user, setUser] = useState<User>({ email: '' });
// Bootstrap the application with the authenticated user's session data.
useEffect(() => {
const fetchSession = async () => {
try {
// Call your Express server's Session endpoint.
const sessionData = await getSession();
setIsAuthenticated(true);
setUser(sessionData.user);
} catch (error: unknown) {
console.log(error);
// You could alternately perform other actions instead of performing an immediate redirect.
if (isUnauthorized(error)) {
// You might want to preserve the current location here for a better UX.
redirectToLogin(window.location.href);
} else {
redirectToLogout();
}
} finally {
setIsLoading(false);
}
};
fetchSession();
}, []);
return (
// You can expose any state functions or fields as needed by your app.
<AuthContext.Provider value={{ isAuthenticated, isLoading, user, setUser }}>
{children}
</AuthContext.Provider>
);
}
function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth() must be used within an AuthProvider');
}
return context;
}
export { AuthProvider, useAuth };
Use the Auth Provider
Place the AuthProvider
at your app's root to ensure authentication state is available throughout your application and verified on initial load.
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import { AuthProvider } from '@/context';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<AuthProvider>
{children}
</AuthProvider>
</StrictMode>
);
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import { App } from 'app';
import { AuthProvider } from 'context';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<AuthProvider>
<App />
</AuthProvider>
</StrictMode>
);
Protect Frontend Routes and Components
The useAuth()
from your Auth Context hook manages authentication state throughout your app, providing isAuthenticated
and user data. This enables common patterns like conditional rendering of authenticated/unauthenticated views, route protection, or dynamic UI updates based on the user's auth status.
Here are a couple common patterns you can apply as needed (though not an exhaustive list).
Use the Auth State Directly
import React from "react";
import { useAuth } from "@/context/auth-context";
import { redirectToLogin, redirectToLogout } from "@/util/helpers";
function App() {
const { isAuthenticated, user } = useAuth();
const AuthenticatedView = () => (
<>
<h1>Welcome to Wristband Auth, {user.firstName}!</h1>
<button onClick={redirectToLogout}>Logout</button>
</>
);
const UnauthenticatedView = () => (
<>
<h1>Welcome to Wristband Auth</h1>
<button onClick={redirectToLogin}>Login</button>
</>
);
return (
<div>
{isAuthenticated ? <AuthenticatedView /> : <UnauthenticatedView />}
</div>
);
};
export default App;
Create an Auth Guard Component
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Dashboard, Spinner } from "@/components";
import { useAuth } from "@/context/auth-context";
const AuthGuard = ({ children, fallback = null }) => {
const { isAuthenticated } = useAuth();
// Show fallback UI (e.g., a redirect, login prompt, etc.)
if (!isAuthenticated) {
return fallback;
}
return children;
};
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<AuthGuard fallback={<Login />}>
<Dashboard />
</AuthGuard>
}
/>
</Routes>
</BrowserRouter>
);
}
export default App;
You have now integrated Wristband authentication into both your Express.js and React application!
Before we test the authentication flows, let's first determine if your application needs to configure CORS.
Updated 1 day ago