## Use AI to integrate Auth0

If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).**Install:**

```
npx skills add auth0/agent-skills --skill auth0
```

**Then ask your AI assistant:**

```
Add Auth0 authentication to my React app
```

Your AI assistant will automatically create your Auth0 application, fetch credentials, install `@auth0/auth0-react`, configure the Auth0Provider, and create all necessary components. [Full agent skills documentation →](/content/docs/quickstart/agent-skills/index.html)

**Prerequisites:** Before you begin, ensure you have the following installed:

- **[Node.js](https://nodejs.org/en/download)** 20 LTS or newer
- **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ or **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ or **[pnpm](https://pnpm.io/installation)** 8+

Verify installation: `node --version && npm --version`**React Version Compatibility:** This quickstart works with **React 18.x** and newer.

## Get Started

This quickstart demonstrates how to add Auth0 authentication to a React application. You’ll build a secure single-page app with login, logout, and user profile features using the Auth0 React SDK.

1. Create a new project

Create a new React project for this Quickstart

```
npm create vite@latest auth0-react -- --template react-ts
```

Open the project

```
   cd auth0-react
   ```

2. Install the Auth0 React SDK

```
npm add @auth0/auth0-react && npm install
```

3. Setup your Auth0 App

Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project. You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:

- Quick Setup (recommended)
   - CLI
   - Dashboard

Create an Auth0 App and copy the pre-filled `.env` file with the right configuration values.

Log into create the app

**.env**
   ```
   VITE_AUTH0_DOMAIN={yourDomain}
   VITE_AUTH0_CLIENT_ID={yourClientId}
   ```

Run the following command in your project’s root directory to create an Auth0 app and generate a `.env` file:

Mac
   ```
   # Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0

# Set up Auth0 app and generate .env file
auth0 qs setup --app --type spa --framework react --build-tool vite --name "My App" --port 5173
```

Windows
   ```
   # Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0

# Set up Auth0 app and generate .env file
auth0 qs setup --app --type spa --framework react --build-tool vite --name "My App" --port 5173
```

Before you start, create a `.env` file on your project’s root directory

**.env**
   ```
   VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
   VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
   ```

1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
   2. Click on **Applications** > **Applications** > **Create Application**
   3. In the popup, enter a name for your app, select `Single Page Web Application` as the app type and click **Create**
   4. Switch to the **Settings** tab on the Application Details page
   5. Replace `YOUR_AUTH0_APP_DOMAIN` and `YOUR_AUTH0_APP_CLIENT_ID` on the `.env` file with the **Domain** and **Client ID** values from the dashboard

Finally, on the **Settings** tab of your Application Details page, configure the following URLs:**Allowed Callback URLs:**
   ```
   http://localhost:5173
   ```
   **Allowed Logout URLs:**
   ```
   http://localhost:5173
   ```
   **Allowed Web Origins:**
   ```
   http://localhost:5173
   ```

**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app. **Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page. **Allowed Web Origins** is critical for silent authentication. Without it, users will be logged out when they refresh the page or return to your app later.
   Verify your `.env` file exists: `cat .env` (Mac/Linux) or `type .env` (Windows)

4. Add the provider

**src/main.tsx**
   ```
   import { StrictMode } from 'react';
   import { createRoot } from 'react-dom/client';
   import './index.css'; // Importing the main CSS file
   import App from './App.tsx';
   import { Auth0Provider } from '@auth0/auth0-react';

createRoot(document.getElementById('root')!).render(
     <StrictMode>
       <Auth0Provider
         domain={import.meta.env.VITE_AUTH0_DOMAIN}
         clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
         authorizationParams={{
           redirect_uri: window.location.origin
         }}
       >
         <App />
       </Auth0Provider>
     </StrictMode>
   );
   ```

5. Create Login, Logout and Profile Components

Create files

Mac/Linux
   ```
   touch src/LoginButton.tsx && touch src/LogoutButton.tsx && touch src/Profile.tsx
   ```

Windows
   ```
   New-Item -ItemType File -Path src/LoginButton.tsx
   New-Item -ItemType File -Path src/LogoutButton.tsx
   New-Item -ItemType File -Path src/Profile.tsx
   ```

And add the following code snippets:

**src/LoginButton.tsx**
   ```
   import { useAuth0 } from "@auth0/auth0-react";

const LoginButton = () => {
     const { loginWithRedirect } = useAuth0();
     return (
       <button
         onClick={() => loginWithRedirect()}
         className="button login"
       >
         Log In
       </button>
     );
   };

export default LoginButton;
   ```
   
   **src/LogoutButton.tsx**
   ```
   import { useAuth0 } from "@auth0/auth0-react";

const LogoutButton = () => {
     const { logout } = useAuth0();
     return (
       <button
         onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
         className="button logout"
       >
         Log Out
       </button>
     );
   };

export default LogoutButton;
   ```

**src/Profile.tsx**
   ```
   import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
     const { user, isAuthenticated, isLoading } = useAuth0();

if (isLoading) {
       return <div className="loading-text">Loading profile...</div>;
     }

return (
       isAuthenticated && user ? (
         <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '1rem' }}>
           <img
             src={user.picture || `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`}
             alt={user.name || 'User'}
             className="profile-picture"
             style={{
               width: '110px',
               height: '110px',
               borderRadius: '50%',
               objectFit: 'cover',
               border: '3px solid #63b3ed'
             }}
             onError={(e) => {
               const target = e.target;
               target.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`;
             }}
           />
           <div style={{ textAlign: 'center' }}>
             <div className="profile-name" style={{ fontSize: '2rem', fontWeight: '600', color: '#f7fafc', marginBottom: '0.5rem' }}>
               {user.name}
             </div>
             <div className="profile-email" style={{ fontSize: '1.15rem', color: '#a0aec0' }}>
               {user.email}
             </div>
           </div>
         </div>
       ) : null
     );
   };

export default Profile;
   ```

**src/App.tsx**
   ```
   import { useAuth0 } from '@auth0/auth0-react';
   import LoginButton from './LoginButton';
   import LogoutButton from './LogoutButton';
   import Profile from './Profile';

function App() {
     const { isAuthenticated, isLoading, error } = useAuth0();

if (isLoading) {
       return (
         <div className="app-container">
           <div className="loading-state">
             <div className="loading-text">Loading...</div>
           </div>
         </div>
       );
     }

if (error) {
       return (
         <div className="app-container">
           <div className="error-state">
             <div className="error-title">Oops!</div>
             <div className="error-message">Something went wrong</div>
             <div className="error-sub-message">{error.message}</div>
           </div>
         </div>
       );
     }

return (
       <div className="app-container">
         <div className="main-card-wrapper">
           <img
             src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png"
             alt="Auth0 Logo"
             className="auth0-logo"
             onError={(e) => {
               e.currentTarget.style.display = 'none';
             }}
           />
           <h1 className="main-title">Welcome to Sample0</h1>

{isAuthenticated ? (
             <div className="logged-in-section">
               <div className="logged-in-message">✅ Successfully authenticated!</div>
               <h2 className="profile-section-title">Your Profile</h2>
               <div className="profile-card">
                 <Profile />
               </div>
               <LogoutButton />
             </div>
           ) : (
             <div className="action-card">
               <p className="action-text">Get started by signing in to your account</p>
               <LoginButton />
             </div>
           )}
         </div>
       </div>
     );
   }

export default App;
   ```

6. Run your app

```
npm run dev
```

If port 5173 is in use, run: `npm run dev -- --port 5174` and update your Auth0 app’s callback URLs to `http://localhost:5174`

**Checkpoint** You should now have a fully functional Auth0 login page running on your [localhost](http://localhost:5173/)

## Advanced Usage

### Protecting Routes with React Router

Use Auth0’s authentication state to protect specific routes in your application:

**src/App.jsx**
   ```
   import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
   import { useAuth0 } from '@auth0/auth0-react';
   import Profile from './components/Profile';
   import Dashboard from './components/Dashboard';
   import LoginButton from './components/LoginButton';

function ProtectedRoute({ children }) {
     const { isAuthenticated, isLoading } = useAuth0();

if (isLoading) return <div>Loading...</div>;

return isAuthenticated ? children : <Navigate to="/" />;
   }

function App() {
     return (
       <BrowserRouter>
         <Routes>
           <Route path="/" element={<LoginButton />} />
           <Route
             path="/profile"
             element={
               <ProtectedRoute>
                 <Profile />
               </ProtectedRoute>
             }
           />
           <Route
             path="/dashboard"
             element={
               <ProtectedRoute>
                 <Dashboard />
               </ProtectedRoute>
             }
           />
         </Routes>
       </BrowserRouter>
     );
   }
   ```

### Calling Protected APIs

Configure your Auth0Provider to include an API audience and use the `getAccessTokenSilently` method:

**src/main.jsx**
   ```
   import { Auth0Provider } from '@auth0/auth0-react';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
     <Auth0Provider
       domain={import.meta.env.VITE_AUTH0_DOMAIN}
       clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
       authorizationParams={{
         redirect_uri: window.location.origin,
         audience: "YOUR_API_IDENTIFIER"
       }}
     >
       <App />
     </Auth0Provider>
   );
   ```

Then make authenticated API calls:

**src/components/ApiCall.jsx**
   ```
   import { useState } from 'react';
   import { useAuth0 } from '@auth0/auth0-react';

function ApiCall() {
     const { getAccessTokenSilently } = useAuth0();
     const [apiResponse, setApiResponse] = useState(null);

const callProtectedApi = async () => {
       try {
         const token = await getAccessTokenSilently();

const response = await fetch('/api/protected', {
           headers: {
             Authorization: `Bearer ${token}`
           }
         });

const data = await response.json();
         setApiResponse(data);
       } catch (error) {
         console.error('API call failed:', error);
       }
     };

return (
       <div>
         <button onClick={callProtectedApi}>Call API</button>
         {apiResponse && <pre>{JSON.stringify(apiResponse, null, 2)}</pre>}
       </div>
     );
   }

export default ApiCall;
   ```

### Using Auth0 with Custom Hooks

Create reusable custom hooks for common authentication patterns:

**src/hooks/useAuthenticatedUser.js**
   ```
   import { useAuth0 } from '@auth0/auth0-react';
   import { useEffect, useState } from 'react';

export function useAuthenticatedUser() {
     const { user, isAuthenticated, isLoading, getAccessTokenSilently } = useAuth0();
     const [accessToken, setAccessToken] = useState(null);

useEffect(() => {
       if (isAuthenticated && !isLoading) {
         getAccessTokenSilently()
           .then(token => setAccessToken(token))
           .catch(console.error);
       }
     }, [isAuthenticated, isLoading, getAccessTokenSilently]);

return {
       user,
       accessToken,
       isAuthenticated,
       isLoading
     };
   }
   ```

Usage in components:
   **src/components/UserDashboard.jsx**
   ```
   import { useAuthenticatedUser } from '../hooks/useAuthenticatedUser';

function UserDashboard() {
     const { user, accessToken, isLoading } = useAuthenticatedUser();

if (isLoading) return <div>Loading...</div>;

return (
       <div>
         <h1>Welcome, {user?.name}</h1>
         <p>Access Token: {accessToken ? 'Available' : 'Not available'}</p>
       </div>
     );
   }
   ```
