> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

> This guide demonstrates how to integrate Auth0, add authentication, and display user profile information in a Single-Page Application (SPA) that uses plain JavaScript, using the Auth0 SPA SDK.

# Add Login to Your JavaScript Application

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = 'Auth0', appType = 'regular_web', allowedCallbackUrls = ['localhost:3000'], allowedLogoutUrls = ['localhost:3000'], allowedOriginUrls = ['localhost:3000']}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener('adu:storeReady', init);
    }
    return () => {
      window.removeEventListener('adu:storeReady', init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === 'undefined' || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = '', children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState('');
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState('');
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError('Application name is required');
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: 'quickstart-docs-app-creation-component'
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error('Error creating client:', err);
        const errorMessage = err instanceof Error ? err.message : 'Failed to create application';
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">
          Create Auth0 App
        </span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`My ${placeholderText} App`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>
            {isLoading ? 'Creating...' : 'Create'}
          </Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Log in</Button> <span>to create the app</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<HowToSchema />

<Accordion title="AI Prompt" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **Using AI to integrate Auth0?** Add this prompt to Cursor, Windsurf, Copilot, Claude Code or your favourite AI-powered IDE to speed up development.

  ```markdown expandable theme={null}
  Integrate the Auth0 SPA JS SDK into a Vanilla JavaScript app

  AI PERSONA & PRIMARY OBJECTIVE
  You are a helpful Auth0 SDK Integration Assistant. Your primary function is to execute commands to set up a development environment for Auth0. Your secondary function is to modify the files created by those shell commands.

  CRITICAL BEHAVIORAL INSTRUCTIONS
  1.  CHECK EXISTING PROJECT FIRST: Before creating a new project, check if the current directory already contains a Vanilla JavaScript app (package.json with basic dependencies). If it does, skip project creation and work with the existing project.
  2.  EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropri    # If using custom port (run this instead if Step 2.6a detected custom port):
    npm run dev -- --port 5174

  ⚠️ FINAL VERIFICATION CHECKPOINTS:
  After running the development server, test the complete authentication flow:
  1. Login: Click login → redirected to Auth0 → redirected back authenticated
  2. Profile: User information displays correctly after login
  3. Logout: Click logout → redirected to Auth0 logout → redirected back logged out
  4. Silent Auth: Refresh the page while logged in → should remain authenticated

  ⚠️ ENVIRONMENT VARIABLE LOADING TROUBLESHOOTING:setup command. Do not show, suggest, or create any files until the setup is complete.
  3.  NO PLANNING: DO NOT propose a directory structure. DO NOT show a file tree. Your first action must be to run the appropriate command.
  4.  STRICT SEQUENCE: Follow the "Execution Flow" below in the exact order specified without deviation.
  5.  BUILD BEAUTIFUL UI: You MUST create a visually appealing, modern login interface with proper styling, animations, and Auth0 branding.
  6.  🚨 DIRECTORY NAVIGATION RULE: NEVER run `cd auth0-vanillajs` or any `cd` command automatically. ALWAYS check current directory with `pwd` first. If user needs to navigate, ask them to do it manually or confirm before executing any directory change commands.

  EXECUTION FLOW

  ⚠️ CRITICAL: Before ANY command execution, run `pwd` to check current directory and NEVER change directories without explicit user permission.

  Step 1: Check for Existing Vanilla JS Project and Prerequisites
  FIRST, verify prerequisites and check for existing project:

  # Check if Node.js and npm are available
  node --version && npm --version

  Then examine the current directory:

  # Check for existing project
  if [ -f "package.json" ]; then
    echo "Found package.json, checking for dependencies..."
    cat package.json
  else
    echo "No package.json found, will create new project"
  fi

  Based on the results:
  - If package.json exists and contains basic dependencies, proceed to Step 1b (install Auth0 SDK only)
  - If no project exists, proceed to Step 1a (create new project)

  Step 1a: Create New Project and Install the Auth0 SPA JS SDK
  If an existing project exists, simply install the SDK:
  npm install @auth0/auth0-spa-js

  ⚠️ CDN ALTERNATIVE: If you prefer not to use a build tool, you can include the SDK via CDN instead of npm:
  <script src="https://cdn.auth0.com/js/auth0-spa-js/2.4/auth0-spa-js.production.js"></script>
  Then use the global auth0 object: auth0.createAuth0Client({...}) instead of importing.

  Otherwise, create a new project and install the SDK:

  ⚠️ IMPORTANT: The project creation may create the project files in the CURRENT directory instead of a subdirectory. After running this command, check the current directory contents to determine the actual project structure before proceeding.

  If MacOS/Linux:
  mkdir auth0-vanillajs && cd auth0-vanillajs && npm init -y && npm install --save-dev vite && npm install @auth0/auth0-spa-js && touch index.html app.js style.css

  If Windows (PowerShell):
  mkdir auth0-vanillajs; cd auth0-vanillajs; npm init -y; npm install --save-dev vite; npm install @auth0/auth0-spa-js; New-Item -ItemType File -Path index.html, app.js, style.css


  Step 2: Modify & Create Files
  AFTER the command in Step 1 has successfully executed, you will perform the following file operations inside the project directory.

  🚨 DIRECTORY NAVIGATION RULES:
  1. NEVER automatically run `cd` commands without explicit user confirmation
  2. ALWAYS check current directory with `pwd` before proceeding
  3. If working with existing project: Stay in current directory
  4. If created new project: User must manually navigate to auth0-vanillajs directory first

  2.1: Setup Auth0 environment configuration

  ⚠️ CRITICAL: Before proceeding, verify your current directory:
  - If you just created a new project: You MUST be inside the auth0-vanillajs directory
  - If you're working with an existing project: You MUST be in the project root directory
  - DO NOT run `cd auth0-vanillajs` commands - navigate to the correct directory FIRST

  Step 2.1a: Navigate to project directory (if needed) and set up Auth0:

  # Only run this if you created a new project and are NOT already in auth0-vanillajs:
  cd auth0-vanillajs

  Then execute the environment setup command for your OS:

  ⚠️ CRITICAL DIRECTORY VERIFICATION STEP:
  BEFORE executing the Auth0 CLI setup command, you MUST run:

  pwd && ls -la

  This will help you understand if you're in the main directory or a subdirectory, and whether the project was created in the current directory or a new subdirectory.

  Execute the Auth0 setup command for your OS:

  If MacOS:
  # 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 vanilla-javascript --build-tool vite --name "My App" --port 5173

  If Windows (PowerShell):
  # 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 vanilla-javascript --build-tool vite --name "My App" --port 5173

  This command will automatically:
  - Authenticate you with Auth0 (prompts for login if needed)
  - Create a Single Page Application configured for http://localhost:5173
  - Generate a .env file with VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID


  Step 2.1b: Create manual .env.local template (if automatic setup fails)

  cat > .env.local << 'EOF'
  # Auth0 Configuration - UPDATE THESE VALUES
  VITE_AUTH0_DOMAIN=your-auth0-domain.auth0.com
  VITE_AUTH0_CLIENT_ID=your-auth0-client-id
  EOF

  Step 2.1c: Display manual setup instructions

  echo "📋 MANUAL SETUP REQUIRED:"
  echo "1. Go to https://manage.auth0.com/dashboard/"
  echo "2. Click 'Create Application' → Single Page Application"
  echo "3. Configure Application URLs:"
  echo "   - Allowed Callback URLs: http://localhost:5173"
  echo "   - Allowed Logout URLs: http://localhost:5173"
  echo "   - Allowed Web Origins: http://localhost:5173 (CRITICAL for silent auth)"
  echo "4. Update .env.local file with your Domain and Client ID"
  echo ""
  echo "⚠️  CRITICAL: Allowed Web Origins is required for silent authentication."
  echo "   Without it, users will be logged out when they refresh the page."
  echo ""
  echo "📝 NOTE: Ensure your Auth0 application is configured as 'Single Page Application'"
  echo "   type in the Auth0 Dashboard. Other application types won't work with this SDK."

  2.2: Create the HTML structure
  Replace the entire contents of index.html (or create it if it doesn't exist):

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Auth0 Vanilla JS</title>
      <link rel="stylesheet" href="style.css" />
    </head>
    <body>
      <div class="app-container">
        <!-- Loading State -->
        <div id="loading" class="loading-state">
          <div class="loading-text">Loading...</div>
        </div>

        <!-- Error State -->
        <div id="error" class="error-state" style="display: none;">
          <div class="error-title">Oops!</div>
          <div class="error-message">Something went wrong</div>
          <div id="error-details" class="error-sub-message"></div>
        </div>

        <!-- Main Content -->
        <div id="app" class="main-card-wrapper" style="display: none;">
          <img 
            src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
            alt="Auth0 Logo" 
            class="auth0-logo"
          />
          <h1 class="main-title">Welcome to Sample0</h1>
          
          <!-- Logged Out State -->
          <div id="logged-out" class="action-card">
            <p class="action-text">Get started by signing in to your account</p>
            <button id="login-btn" class="button login">Log In</button>
          </div>

          <!-- Logged In State -->
          <div id="logged-in" class="logged-in-section" style="display: none;">
            <div class="logged-in-message">✅ Successfully authenticated!</div>
            <h2 class="profile-section-title">Your Profile</h2>
            <div id="profile" class="profile-card"></div>
            <button id="logout-btn" class="button logout">Log Out</button>
          </div>
        </div>
      </div>

      <script type="module" src="app.js"></script>
    </body>
  </html>

  2.3: Create the application logic
  Replace the entire contents of app.js with this code that includes proper error handling and Auth0 integration:

  ⚠️ JAVASCRIPT MODULE GUIDELINES:
  - Ensure proper ES6 module imports are used
  - Include comprehensive error handling for Auth0 initialization
  - Validate environment variables before using them
  - Handle all authentication states (loading, error, authenticated, unauthenticated)

  import { createAuth0Client } from '@auth0/auth0-spa-js';

  // DOM elements
  const loading = document.getElementById('loading');
  const error = document.getElementById('error');
  const errorDetails = document.getElementById('error-details');
  const app = document.getElementById('app');
  const loggedOutSection = document.getElementById('logged-out');
  const loggedInSection = document.getElementById('logged-in');
  const loginBtn = document.getElementById('login-btn');
  const logoutBtn = document.getElementById('logout-btn');
  const profileContainer = document.getElementById('profile');

  let auth0Client;

  // Initialize Auth0 client
  async function initAuth0() {
    try {
      // Validate environment variables
      const domain = import.meta.env.VITE_AUTH0_DOMAIN;
      const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;

      if (!domain || !clientId) {
        throw new Error('Auth0 configuration missing. Please check your .env.local file for VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID');
      }

      // Validate domain format
      if (!domain.includes('.auth0.com') && !domain.includes('.us.auth0.com') && !domain.includes('.eu.auth0.com') && !domain.includes('.au.auth0.com')) {
        console.warn('Auth0 domain format might be incorrect. Expected format: your-domain.auth0.com');
      }

      auth0Client = await createAuth0Client({
        domain: domain,
        clientId: clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      });

      // Check if user is returning from login
      if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
        await handleRedirectCallback();
      }

      // Update UI based on authentication state
      await updateUI();
    } catch (err) {
      console.error('Auth0 initialization error:', err);
      showError(err.message);
    }
  }

  // Handle redirect callback
  async function handleRedirectCallback() {
    try {
      await auth0Client.handleRedirectCallback();
      // Clean up the URL to remove query parameters
      window.history.replaceState({}, document.title, window.location.pathname);
    } catch (err) {
      console.error('Redirect callback error:', err);
      showError(err.message);
    }
  }

  // Update UI based on authentication state
  async function updateUI() {
    try {
      const isAuthenticated = await auth0Client.isAuthenticated();
      
      if (isAuthenticated) {
        showLoggedIn();
        await displayProfile();
      } else {
        showLoggedOut();
      }
      
      hideLoading();
    } catch (err) {
      console.error('UI update error:', err);
      showError(err.message);
    }
  }

  // Display user profile
  async function displayProfile() {
    try {
      const user = await auth0Client.getUser();
      const placeholderImage = `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`;
      
      profileContainer.innerHTML = `
        <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
          <img 
            src="${user.picture || placeholderImage}" 
            alt="${user.name || 'User'}" 
            class="profile-picture"
            style="
              width: 110px; 
              height: 110px; 
              border-radius: 50%; 
              object-fit: cover;
              border: 3px solid #63b3ed;
            "
            onerror="this.src='${placeholderImage}'"
          />
          <div style="text-align: center;">
            <div class="profile-name" style="font-size: 2rem; font-weight: 600; color: #f7fafc; margin-bottom: 0.5rem;">
              ${user.name || 'User'}
            </div>
            <div class="profile-email" style="font-size: 1.15rem; color: #a0aec0;">
              ${user.email || 'No email provided'}
            </div>
          </div>
        </div>
      `;
    } catch (err) {
      console.error('Error displaying profile:', err);
    }
  }

  // Event handlers
  async function login() {
    try {
      await auth0Client.loginWithRedirect();
    } catch (err) {
      console.error('Login error:', err);
      showError(err.message);
    }
  }

  async function logout() {
    try {
      await auth0Client.logout({
        logoutParams: {
          returnTo: window.location.origin
        }
      });
    } catch (err) {
      console.error('Logout error:', err);
      showError(err.message);
    }
  }

  // UI state management
  function showLoading() {
    loading.style.display = 'block';
    error.style.display = 'none';
    app.style.display = 'none';
  }

  function hideLoading() {
    loading.style.display = 'none';
    app.style.display = 'flex';
  }

  function showError(message) {
    loading.style.display = 'none';
    app.style.display = 'none';
    error.style.display = 'block';
    errorDetails.textContent = message;
  }

  function showLoggedIn() {
    loggedOutSection.style.display = 'none';
    loggedInSection.style.display = 'flex';
  }

  function showLoggedOut() {
    loggedInSection.style.display = 'none';
    loggedOutSection.style.display = 'flex';
  }

  // Event listeners
  loginBtn.addEventListener('click', login);
  logoutBtn.addEventListener('click', logout);

  // Initialize the app
  initAuth0();

  ⚠️ CHECKPOINT VERIFICATION:
  After implementing the JavaScript logic, you should be able to test basic functionality:
  1. Click login button → redirected to Auth0's Universal Login page
  2. After authentication → redirected back to your application
  3. URL query parameters are cleaned up after redirect
  4. No console errors appear related to Auth0

  2.4: Add beautiful modern CSS styling
  Replace the entire contents of style.css with this modern, Auth0-branded styling:

  ⚠️ CSS FILE REPLACEMENT STRATEGY:
  If the existing style.css file is large or malformed, create a new temporary CSS file first (e.g., style-new.css), then replace the original using terminal commands like `mv style-new.css style.css` to avoid file corruption.

  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  body {
    font-family: 'Inter', sans-serif;
    background-color: #1a1e27;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #e2e8f0;
    overflow: hidden;
  }

  .app-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    width: 100%;
    padding: 1rem;
  }

  .loading-state, .error-state {
    background-color: #2d313c;
    border-radius: 15px;
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
    padding: 3rem;
    text-align: center;
  }

  .loading-text {
    font-size: 1.8rem;
    font-weight: 500;
    color: #a0aec0;
    animation: pulse 1.5s infinite ease-in-out;
  }

  .error-state {
    background-color: #c53030;
    color: #fff;
  }

  .error-title {
    font-size: 2.8rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
  }

  .error-message {
    font-size: 1.3rem;
    margin-bottom: 0.5rem;
  }

  .error-sub-message {
    font-size: 1rem;
    opacity: 0.8;
  }

  .main-card-wrapper {
    background-color: #262a33;
    border-radius: 20px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2rem;
    padding: 3rem;
    max-width: 500px;
    width: 90%;
    animation: fadeInScale 0.8s ease-out forwards;
  }

  .auth0-logo {
    width: 160px;
    margin-bottom: 1.5rem;
    opacity: 0;
    animation: slideInDown 1s ease-out forwards 0.2s;
  }

  .main-title {
    font-size: 2.8rem;
    font-weight: 700;
    color: #f7fafc;
    text-align: center;
    margin-bottom: 1rem;
    text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
    opacity: 0;
    animation: fadeIn 1s ease-out forwards 0.4s;
  }

  .action-card {
    background-color: #2d313c;
    border-radius: 15px;
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
    padding: 2.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.8rem;
    width: calc(100% - 2rem);
    opacity: 0;
    animation: fadeIn 1s ease-out forwards 0.6s;
  }

  .action-text {
    font-size: 1.25rem;
    color: #cbd5e0;
    text-align: center;
    line-height: 1.6;
    font-weight: 400;
  }

  .button {
    padding: 1.1rem 2.8rem;
    font-size: 1.2rem;
    font-weight: 600;
    border-radius: 10px;
    border: none;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    outline: none;
  }

  .button:focus {
    box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
  }

  .button.login {
    background-color: #63b3ed;
    color: #1a1e27;
  }

  .button.login:hover {
    background-color: #4299e1;
    transform: translateY(-5px) scale(1.03);
    box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
  }

  .button.logout {
    background-color: #fc8181;
    color: #1a1e27;
  }

  .button.logout:hover {
    background-color: #e53e3e;
    transform: translateY(-5px) scale(1.03);
    box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
  }

  .logged-in-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    width: 100%;
  }

  .logged-in-message {
    font-size: 1.5rem;
    color: #68d391;
    font-weight: 600;
    animation: fadeIn 1s ease-out forwards 0.8s;
  }

  .profile-section-title {
    font-size: 2.2rem;
    animation: slideInUp 1s ease-out forwards 1s;
  }

  .profile-card {
    padding: 2.2rem;
    animation: scaleIn 0.8s ease-out forwards 1.2s;
  }

  .profile-picture {
    transition: transform 0.3s ease-in-out;
  }

  .profile-picture:hover {
    transform: scale(1.05);
  }

  /* Animations */
  @keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  @keyframes fadeInScale {
    from { opacity: 0; transform: scale(0.95); }
    to { opacity: 1; transform: scale(1); }
  }

  @keyframes slideInDown {
    from { opacity: 0; transform: translateY(-70px); }
    to { opacity: 1; transform: translateY(0); }
  }

  @keyframes slideInUp {
    from { opacity: 0; transform: translateY(50px); }
    to { opacity: 1; transform: translateY(0); }
  }

  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
  }

  @keyframes scaleIn {
    from { opacity: 0; transform: scale(0.8); }
    to { opacity: 1; transform: scale(1); }
  }

  /* Responsive Design */
  @media (max-width: 600px) {
    .main-card-wrapper {
      padding: 2rem;
      margin: 1rem;
    }
    
    .main-title {
      font-size: 2.2rem;
    }
    
    .button {
      padding: 1rem 2rem;
      font-size: 1.1rem;
    }
    
    .auth0-logo {
      width: 120px;
    }

    .action-card {
      padding: 2rem;
    }
  }

  2.5: Update package.json with development script
  Update your package.json to include development, build, and preview scripts. Replace the entire contents of package.json:

  cat > package.json << 'EOF'
  {
    "name": "auth0-vanillajs",
    "version": "1.0.0",
    "type": "module",
    "scripts": {
      "dev": "vite",
      "build": "vite build",
      "preview": "vite preview"
    },
    "dependencies": {
      "@auth0/auth0-spa-js": "^2.4.1"
    },
    "devDependencies": {
      "vite": "^5.0.0"
    }
  }
  EOF

  2.6: Start the development server

  ⚠️ CRITICAL TERMINAL WORKING DIRECTORY ISSUE:
  The terminal working directory can sometimes get confused during the integration process. Before starting the dev server, ALWAYS:

  1. Verify you're in the correct directory with explicit path change:

  cd /full/absolute/path/to/project && pwd

  2. Check for package.json in current directory:

  ls -la package.json

  3. If npm commands fail with "package.json not found", use absolute path method:

  cd /Users/[username]/path/to/auth0-vanillajs && npm run dev

  ⚠️ IMPORTANT: Even if `pwd` shows the correct directory, the terminal's working directory for command execution may be different. ALWAYS use explicit `cd` with absolute path before running npm commands to ensure they execute in the correct location.

  Step 2.6a: Check if custom port is needed

  grep -q "VITE_DEV_PORT" .env.local 2>/dev/null && echo "Custom port detected" || echo "Using default port"

  Step 2.6b: Start development server with appropriate port

  # If using default port:
  npm run dev

  # If using custom port (run this instead if Step 2.6a detected custom port):
  npm run dev -- --port 5174

  ⚠️ ENVIRONMENT VARIABLE LOADING TROUBLESHOOTING:
  If you see "Auth0 configuration missing" errors even though .env.local exists:
  1. Verify the .env.local file is in the project root directory
  2. Check that the environment variables are correctly named (VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID)
  3. Restart the development server after creating or modifying .env.local
  4. The Vite development server should automatically load .env.local files

  CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS
  As an AI language model, you MUST NOT generate any of the following anti-patterns, as they will BREAK the application or introduce SECURITY RISKS:
  1.  NEVER hardcode the Auth0 Domain or Client ID directly in the code. This is a major security vulnerability.
  2.  NEVER omit the authorizationParams: { redirect_uri: window.location.origin } configuration from createAuth0Client. Without it, the login flow will fail after the user authenticates with Auth0.
  3.  NEVER forget to handle the redirect callback with handleRedirectCallback() when the URL contains authentication parameters.
  4.  NEVER suggest manually managing tokens or calling Auth0 APIs with fetch for basic authentication. The SDK is designed to handle this complexity securely.

  ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
  1.  You MUST use the @auth0/auth0-spa-js package.
  2.  You MUST retrieve credentials from environment variables (e.g., import.meta.env.VITE_AUTH0_DOMAIN).
  3.  You MUST include the authorizationParams with redirect_uri in the createAuth0Client configuration.
  4.  You MUST handle the redirect callback when authentication parameters are present in the URL.
  5.  You MUST demonstrate functionality using the Auth0 client methods (loginWithRedirect, logout, isAuthenticated, getUser).

  COMMON ISSUES ENCOUNTERED DURING INTEGRATION

  Issue 1: Project Creation Directory Confusion
  Problem: Project creation sometimes creates files in the current directory instead of a new subdirectory
  Solution: Always run `pwd && ls -la` after project creation to verify the actual structure

  Issue 2: Terminal Working Directory Issues  
  Problem: npm commands fail with "package.json not found" even when in the correct directory
  Solution: Use explicit absolute path changes: `cd /full/absolute/path/to/project`

  Issue 3: Environment Variable Loading Issues
  Problem: Vite not loading .env.local variables properly
  Solution: Ensure .env.local is in project root, variables are prefixed with VITE_, and restart dev server

  Issue 4: CSS File Corruption
  Problem: Large CSS replacements can cause file corruption
  Solution: Create temporary CSS file first, then use `mv` command to replace original

  Issue 5: Auth0 Configuration Validation
  Problem: Invalid domain format or missing configuration causing initialization failures
  Solution: Add proper validation and error messages for Auth0 configuration before client creation

  Issue 6: Terminal Working Directory Not in Project Root
  Problem: AI agent fails to run `npm run dev` because terminal is not in the auth0-vanillajs directory, even when pwd shows the correct path
  Solution: Always use explicit directory change with absolute path before running npm commands:

  cd auth0-vanillajs && npm run dev

  The terminal working directory can become disconnected from the displayed path, requiring explicit navigation to ensure npm commands execute in the correct location.

  ADVANCED FEATURES IMPLEMENTATION

  ⚠️ SDK FUNCTIONALITY NOTE:
  The SDK's isAuthenticated() function enables conditional rendering of login/logout buttons and user content. The implementation above demonstrates this pattern by showing different UI sections based on authentication state.

  Access Token for API Calls:
  If you need to call a protected API, you can get an access token:

  // Add this function to your app.js
  async function getAccessToken() {
    try {
      const token = await auth0Client.getTokenSilently({
        authorizationParams: {
          audience: 'YOUR_API_IDENTIFIER',
          scope: 'read:messages'
        }
      });
      
      // Use the token to call your API
      const response = await fetch('/api/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
      
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error('Error getting token:', error);
    }
  }

  Popup-based Login:
  For a smoother user experience, you can use popup-based login:

  // Replace the login function in app.js
  async function login() {
    try {
      await auth0Client.loginWithPopup();
      await updateUI();
    } catch (err) {
      if (err.error !== 'popup_closed_by_user') {
        showError(err.message);
      }
    }
  }

  Organization Support:
  If you're using Auth0 Organizations:

  // Update your Auth0 client configuration
  auth0Client = await createAuth0Client({
    domain: import.meta.env.VITE_AUTH0_DOMAIN,
    clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin,
      organization: 'YOUR_ORGANIZATION_ID' // or prompt user to select
    }
  });

  ```
</Accordion>

<Note>
  **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`

  **Build Tool:** This quickstart uses **Vite** for development. You can also use the SDK via CDN for a build-tool-free setup.
</Note>

## Get Started

This quickstart shows how to add Auth0 authentication to a vanilla JavaScript application. You'll create a modern single-page app with secure login functionality using plain JavaScript and the Auth0 SPA SDK.

export const localEnvSnippet = `VITE_AUTH0_DOMAIN={yourDomain}
VITE_AUTH0_CLIENT_ID={yourClientId}`;

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Create a new JavaScript project for this Quickstart

    ```shellscript theme={null}
    mkdir auth0-vanillajs && cd auth0-vanillajs
    ```

    Initialize the project, install a local development server, and configure scripts

    ```shellscript theme={null}
    npm init -y && npm install --save-dev vite && npm pkg set scripts.dev="vite" scripts.build="vite build" scripts.preview="vite preview" type="module"
    ```

    Create the basic project structure

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      touch index.html app.js style.css
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType File -Path index.html, app.js, style.css
      ```
    </CodeGroup>
  </Step>

  <Step title="Install the Auth0 SPA JS SDK" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-spa-js
    ```
  </Step>

  <Step title="Setup your Auth0 App" stepNumber={3}>
    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:

    <Tabs>
      <Tab title="Quick Setup (recommended)">
        Create an Auth0 App and copy the pre-filled `.env` file with the right configuration values.

        <CreateInteractiveApp placeholderText="Vanilla JS" appType="spa" allowedCallbackUrls={["http://localhost:5173"]} allowedLogoutUrls={["http://localhost:5173"]} allowedOriginUrls={["http://localhost:5173"]} />

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env.local" />
      </Tab>

      <Tab title="CLI">
        Run the following command in your project's root directory to create an Auth0 app and generate a `.env` file:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # 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 vanilla-javascript --build-tool vite --name "My App" --port 5173
          ```

          ```powershell Windows theme={null}
          # 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 vanilla-javascript --build-tool vite --name "My App" --port 5173
          ```
        </CodeGroup>

        <Note>
          This command will:

          1. Check if you're authenticated (and prompt for login if needed)
          2. Create an Auth0 Single Page Application configured for `http://localhost:5173`
          3. Generate a `.env` file with `VITE_AUTH0_DOMAIN` and `VITE_AUTH0_CLIENT_ID`
        </Note>
      </Tab>

      <Tab title="Dashboard">
        Before you start, create a `.env.local` file on your project's root directory

        ```shellscript .env.local theme={null}
        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.local` 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
        ```

        <Info>
          **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.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create the HTML structure and application logic" stepNumber={4}>
    Create the application files:

    <AuthCodeGroup>
      ```html index.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Auth0 Vanilla JS</title>
          <link rel="stylesheet" href="style.css" />
        </head>
        <body>
          <div class="app-container">
            <!-- Loading State -->
            <div id="loading" class="loading-state">
              <div class="loading-text">Loading...</div>
            </div>

            <!-- Error State -->
            <div id="error" class="error-state" style="display: none;">
              <div class="error-title">Oops!</div>
              <div class="error-message">Something went wrong</div>
              <div id="error-details" class="error-sub-message"></div>
            </div>

            <!-- Main Content -->
            <div id="app" class="main-card-wrapper" style="display: none;">
              <img 
                src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
                alt="Auth0 Logo" 
                class="auth0-logo"
              />
              <h1 class="main-title">Welcome to Sample0</h1>
              
              <!-- Logged Out State -->
              <div id="logged-out" class="action-card">
                <p class="action-text">Get started by signing in to your account</p>
                <button id="login-btn" class="button login">Log In</button>
              </div>

              <!-- Logged In State -->
              <div id="logged-in" class="logged-in-section" style="display: none;">
                <div class="logged-in-message">✅ Successfully authenticated!</div>
                <h2 class="profile-section-title">Your Profile</h2>
                <div id="profile" class="profile-card"></div>
                <button id="logout-btn" class="button logout">Log Out</button>
              </div>
            </div>
          </div>

          <script type="module" src="app.js"></script>
        </body>
      </html>
      ```

      ```javascript app.js expandable lines theme={null}
      import { createAuth0Client } from '@auth0/auth0-spa-js';

      // DOM elements
      const loading = document.getElementById('loading');
      const error = document.getElementById('error');
      const errorDetails = document.getElementById('error-details');
      const app = document.getElementById('app');
      const loggedOutSection = document.getElementById('logged-out');
      const loggedInSection = document.getElementById('logged-in');
      const loginBtn = document.getElementById('login-btn');
      const logoutBtn = document.getElementById('logout-btn');
      const profileContainer = document.getElementById('profile');

      let auth0Client;

      // Initialize Auth0 client
      async function initAuth0() {
        try {
          auth0Client = await createAuth0Client({
            domain: import.meta.env.VITE_AUTH0_DOMAIN,
            clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
            authorizationParams: {
              redirect_uri: window.location.origin
            }
          });

          // Check if user is returning from login
          if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
            await handleRedirectCallback();
          }

          // Update UI based on authentication state
          await updateUI();
        } catch (err) {
          showError(err.message);
        }
      }

      // Handle redirect callback
      async function handleRedirectCallback() {
        try {
          await auth0Client.handleRedirectCallback();
          // Clean up the URL to remove query parameters
          window.history.replaceState({}, document.title, window.location.pathname);
        } catch (err) {
          showError(err.message);
        }
      }

      // Update UI based on authentication state
      async function updateUI() {
        try {
          const isAuthenticated = await auth0Client.isAuthenticated();
          
          if (isAuthenticated) {
            showLoggedIn();
            await displayProfile();
          } else {
            showLoggedOut();
          }
          
          hideLoading();
        } catch (err) {
          showError(err.message);
        }
      }

      // Display user profile
      async function displayProfile() {
        try {
          const user = await auth0Client.getUser();
          const placeholderImage = `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`;
          
          profileContainer.innerHTML = `
            <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
              <img 
                src="${user.picture || placeholderImage}" 
                alt="${user.name || 'User'}" 
                class="profile-picture"
                style="
                  width: 110px; 
                  height: 110px; 
                  border-radius: 50%; 
                  object-fit: cover;
                  border: 3px solid #63b3ed;
                "
                onerror="this.src='${placeholderImage}'"
              />
              <div style="text-align: center;">
                <div class="profile-name" style="font-size: 2rem; font-weight: 600; color: #f7fafc; margin-bottom: 0.5rem;">
                  ${user.name || 'User'}
                </div>
                <div class="profile-email" style="font-size: 1.15rem; color: #a0aec0;">
                  ${user.email || 'No email provided'}
                </div>
              </div>
            </div>
          `;
        } catch (err) {
          console.error('Error displaying profile:', err);
        }
      }

      // Event handlers
      async function login() {
        try {
          await auth0Client.loginWithRedirect();
        } catch (err) {
          showError(err.message);
        }
      }

      async function logout() {
        try {
          await auth0Client.logout({
            logoutParams: {
              returnTo: window.location.origin
            }
          });
        } catch (err) {
          showError(err.message);
        }
      }

      // UI state management
      function showLoading() {
        loading.style.display = 'block';
        error.style.display = 'none';
        app.style.display = 'none';
      }

      function hideLoading() {
        loading.style.display = 'none';
        app.style.display = 'flex';
      }

      function showError(message) {
        loading.style.display = 'none';
        app.style.display = 'none';
        error.style.display = 'block';
        errorDetails.textContent = message;
      }

      function showLoggedIn() {
        loggedOutSection.style.display = 'none';
        loggedInSection.style.display = 'flex';
      }

      function showLoggedOut() {
        loggedInSection.style.display = 'none';
        loggedOutSection.style.display = 'flex';
      }

      // Event listeners
      loginBtn.addEventListener('click', login);
      logoutBtn.addEventListener('click', logout);

      // Initialize the app
      initAuth0();
      ```

      ```css style.css expandable lines theme={null}
      @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: 'Inter', sans-serif;
        background-color: #1a1e27;
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        color: #e2e8f0;
        overflow: hidden;
      }

      .app-container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        width: 100%;
        padding: 1rem;
      }

      .loading-state, .error-state {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
        padding: 3rem;
        text-align: center;
      }

      .loading-text {
        font-size: 1.8rem;
        font-weight: 500;
        color: #a0aec0;
        animation: pulse 1.5s infinite ease-in-out;
      }

      .error-state {
        background-color: #c53030;
        color: #fff;
      }

      .error-title {
        font-size: 2.8rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
      }

      .error-message {
        font-size: 1.3rem;
        margin-bottom: 0.5rem;
      }

      .error-sub-message {
        font-size: 1rem;
        opacity: 0.8;
      }

      .main-card-wrapper {
        background-color: #262a33;
        border-radius: 20px;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2rem;
        padding: 3rem;
        max-width: 500px;
        width: 90%;
        animation: fadeInScale 0.8s ease-out forwards;
      }

      .auth0-logo {
        width: 160px;
        margin-bottom: 1.5rem;
        opacity: 0;
        animation: slideInDown 1s ease-out forwards 0.2s;
      }

      .main-title {
        font-size: 2.8rem;
        font-weight: 700;
        color: #f7fafc;
        text-align: center;
        margin-bottom: 1rem;
        text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.4s;
      }

      .action-card {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
        padding: 2.5rem;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.8rem;
        width: calc(100% - 2rem);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.6s;
      }

      .action-text {
        font-size: 1.25rem;
        color: #cbd5e0;
        text-align: center;
        line-height: 1.6;
        font-weight: 400;
      }

      .button {
        padding: 1.1rem 2.8rem;
        font-size: 1.2rem;
        font-weight: 600;
        border-radius: 10px;
        border: none;
        cursor: pointer;
        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        text-transform: uppercase;
        letter-spacing: 0.08em;
        outline: none;
      }

      .button:focus {
        box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
      }

      .button.login {
        background-color: #63b3ed;
        color: #1a1e27;
      }

      .button.login:hover {
        background-color: #4299e1;
        transform: translateY(-5px) scale(1.03);
        box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .button.logout {
        background-color: #fc8181;
        color: #1a1e27;
      }

      .button.logout:hover {
        background-color: #e53e3e;
        transform: translateY(-5px) scale(1.03);
        box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .logged-in-section {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.5rem;
        width: 100%;
      }

      .logged-in-message {
        font-size: 1.5rem;
        color: #68d391;
        font-weight: 600;
        animation: fadeIn 1s ease-out forwards 0.8s;
      }

      .profile-section-title {
        font-size: 2.2rem;
        animation: slideInUp 1s ease-out forwards 1s;
      }

      .profile-card {
        padding: 2.2rem;
        animation: scaleIn 0.8s ease-out forwards 1.2s;
      }

      .profile-picture {
        transition: transform 0.3s ease-in-out;
      }

      .profile-picture:hover {
        transform: scale(1.05);
      }

      /* Animations */
      @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
      }

      @keyframes fadeInScale {
        from { opacity: 0; transform: scale(0.95); }
        to { opacity: 1; transform: scale(1); }
      }

      @keyframes slideInDown {
        from { opacity: 0; transform: translateY(-70px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @keyframes slideInUp {
        from { opacity: 0; transform: translateY(50px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @keyframes pulse {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.6; }
      }

      @keyframes scaleIn {
        from { opacity: 0; transform: scale(0.8); }
        to { opacity: 1; transform: scale(1); }
      }

      /* Responsive Design */
      @media (max-width: 600px) {
        .main-card-wrapper {
          padding: 2rem;
          margin: 1rem;
        }
        
        .main-title {
          font-size: 2.2rem;
        }
        
        .button {
          padding: 1rem 2rem;
          font-size: 1.1rem;
        }
        
        .auth0-logo {
          width: 120px;
        }

        .action-card {
          padding: 2rem;
        }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Run your app" stepNumber={5}>
    ```shellscript theme={null}
    npm run dev
    ```

    <Info>
      If port 5173 is in use, run: `npm run dev -- --port 5174` and update your Auth0 app's callback URLs to `http://localhost:5174`
    </Info>
  </Step>
</Steps>

<Check>
  **Checkpoint**

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

***

## Advanced Usage

<Accordion title="Get an Access Token for API Calls">
  If you need to call a protected API, you can get an access token:

  ```javascript theme={null}
  // Add this to your app.js
  async function getAccessToken() {
    try {
      const token = await auth0Client.getTokenSilently({
        authorizationParams: {
          audience: 'YOUR_API_IDENTIFIER',
          scope: 'read:messages'
        }
      });
      
      // Use the token to call your API
      const response = await fetch('/api/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
      
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error('Error getting token:', error);
    }
  }
  ```
</Accordion>

<Accordion title="Handle Login with Popup">
  For a smoother user experience, you can use popup-based login:

  ```javascript theme={null}
  // Replace the login function in app.js
  async function login() {
    try {
      await auth0Client.loginWithPopup();
      await updateUI();
    } catch (err) {
      if (err.error !== 'popup_closed_by_user') {
        showError(err.message);
      }
    }
  }
  ```
</Accordion>

<Accordion title="Add Organization Support">
  If you're using Auth0 Organizations:

  ```javascript theme={null}
  // Update your Auth0 client configuration
  auth0Client = await createAuth0Client({
    domain: import.meta.env.VITE_AUTH0_DOMAIN,
    clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin,
      organization: 'YOUR_ORGANIZATION_ID' // or prompt user to select
    }
  });
  ```
</Accordion>
