> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-quickstart-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Login to Your Angular Application

<Tip>
  **Don't have an Auth0 account?** [Sign up for free](https://auth0.com/signup?utm_source=docs\&utm_medium=quickstart\&utm_campaign=spa-angular) and get started with Auth0's secure authentication and authorization platform.
</Tip>

<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
  Integrate the Auth0 Angular SDK into an Angular 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 an Angular app (package.json with Angular dependencies). If it does, skip project creation and work with the existing project.
  2. EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropriate 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-angular 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 Angular Project and Prerequisites
  FIRST, verify prerequisites and check for existing Angular project:

  Check if Node.js and npm are available
  node --version && npm --version

  Then examine the current directory:

  Check for existing Angular project
  if [ -f "package.json" ]; then
    echo "Found package.json, checking for Angular 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 Angular dependencies, proceed to Step 1b (install Auth0 SDK only)
  If no Angular project exists, proceed to Step 1a (create new project)

  Step 1a: Create New Project and Install the Angular SDK
  If an existing project exists, simply install the SDK:
  npm install @auth0/auth0-angular@latest

  Otherwise, create a new project and install the SDK:

  ⚠️ IMPORTANT: The Angular CLI project creation creates the project in a subdirectory. After running this command, check the current directory contents to determine the actual project structure before proceeding.

  npx @angular/cli@latest new auth0-angular --routing=true --style=css && cd auth0-angular && npm install @auth0/auth0-angular@latest


  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-angular 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-angular directory
  If you're working with an existing project: You MUST be in the project root directory
  DO NOT run cd auth0-angular 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-angular:
  cd auth0-angular

  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.

  If MacOS, execute the following command:
  AUTH0_APP_NAME="My Angular App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t spa -c http://localhost:4200 -l http://localhost:4200 -o http://localhost:4200 --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && mkdir -p src/environments && echo "export const environment = { production: false, auth0: { domain: '${DOMAIN}', clientId: '${CLIENT_ID}' } };" > src/environments/environment.ts && rm auth0-app-details.json && echo "Environment file created at src/environments/environment.ts with your Auth0 details:" && cat src/environments/environment.ts

  If Windows, execute the following command:
  $AppName = "My Angular App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t spa -c http://localhost:4200 -l http://localhost:4200 -o http://localhost:4200 --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; New-Item -ItemType Directory -Force -Path "src\environments"; Set-Content -Path "src\environments\environment.ts" -Value "export const environment = { production: false, auth0: { domain: '$Domain', clientId: '$ClientId' } };"; Remove-Item auth0-app-details.json; Write-Output "Environment file created at src\environments\environment.ts with your Auth0 details:"; Get-Content "src\environments\environment.ts"


  Step 2.1b: Create manual environment template (if automatic setup fails)

  mkdir -p src/environments && cat > src/environments/environment.ts << 'EOF'
  // Auth0 Configuration - UPDATE THESE VALUES
  export const environment = {
    production: false,
    auth0: {
      domain: 'your-auth0-domain.auth0.com',
      clientId: '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. Set Allowed Callback URLs: http://localhost:4200"
  echo "4. Set Allowed Logout URLs: http://localhost:4200"
  echo "5. Set Allowed Web Origins: http://localhost:4200"
  echo "6. Update src/environments/environment.ts file with your Domain and Client ID"

  2.2: Configure the Auth0 module in main.ts
  Replace the entire contents of src/main.ts:

  import { bootstrapApplication } from '@angular/platform-browser';
  import { appConfig } from './app/app.config';
  import { provideAuth0 } from '@auth0/auth0-angular';
  import { mergeApplicationConfig } from '@angular/core';
  import { environment } from './environments/environment';
  import { AppComponent } from './app/app.component';

  // Validate Auth0 configuration
  if (!environment.auth0.domain || !environment.auth0.clientId) {
    console.error("Auth0 configuration missing. Please check your environment.ts file.");
    console.error("Required environment variables:");
    console.error("- auth0.domain");
    console.error("- auth0.clientId");
    throw new Error("Auth0 domain and client ID must be set in environment.ts file");
  }

  // Validate domain format
  if (!environment.auth0.domain.includes('.auth0.com') && !environment.auth0.domain.includes('.us.auth0.com') && !environment.auth0.domain.includes('.eu.auth0.com') && !environment.auth0.domain.includes('.au.auth0.com')) {
    console.warn("Auth0 domain format might be incorrect. Expected format: your-domain.auth0.com");
  }

  const auth0Config = mergeApplicationConfig(appConfig, {
    providers: [
      provideAuth0({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      })
    ]
  });

  bootstrapApplication(AppComponent, auth0Config).catch((err) =>
    console.error(err)
  );

  2.3: Create the component directory structure

  mkdir -p src/app/components

  2.4: Create LoginButton component
  Create src/app/components/login-button.component.ts:

  import { Component, inject } from '@angular/core';
  import { AuthService } from '@auth0/auth0-angular';

  @Component({
    selector: 'app-login-button',
    standalone: true,
    template: `
      <button 
        (click)="loginWithRedirect()" 
        class="button login"
      >
        Log In
      </button>
    `
  })
  export class LoginButtonComponent {
    private auth = inject(AuthService);

    loginWithRedirect(): void {
      this.auth.loginWithRedirect();
    }
  }

  2.5: Create LogoutButton component
  Create src/app/components/logout-button.component.ts:

  import { Component, inject } from '@angular/core';
  import { AuthService } from '@auth0/auth0-angular';

  @Component({
    selector: 'app-logout-button',
    standalone: true,
    template: `
      <button
        (click)="logout()"
        class="button logout"
      >
        Log Out
      </button>
    `
  })
  export class LogoutButtonComponent {
    private auth = inject(AuthService);

    logout(): void {
      this.auth.logout({ 
        logoutParams: { 
          returnTo: window.location.origin 
        } 
      });
    }
  }

  2.6: Create Profile component
  Create src/app/components/profile.component.ts:

  import { Component, inject } from '@angular/core';
  import { AuthService } from '@auth0/auth0-angular';
  import { CommonModule } from '@angular/common';

  @Component({
    selector: 'app-profile',
    standalone: true,
    imports: [CommonModule],
    template: `
      @if (auth.isLoading$ | async) {
        <div class="loading-text">Loading profile...</div>
      }
      
      @if ((auth.isAuthenticated$ | async) && (auth.user$ | async); as user) {
        <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
          @if (user.picture) {
            <img 
              [src]="user.picture" 
              [alt]="user.name || 'User'"
              class="profile-picture"
              style="
                width: 110px; 
                height: 110px; 
                border-radius: 50%; 
                object-fit: cover;
                border: 3px solid #63b3ed;
              "
            />
          }
          <div style="text-align: center;">
            <div 
              class="profile-name" 
              style="
                font-size: 2rem; 
                font-weight: 600; 
                color: #f7fafc; 
                margin-bottom: 0.5rem;
              "
            >
              {{ user.name }}
            </div>
            <div 
              class="profile-email" 
              style="
                font-size: 1.15rem; 
                color: #a0aec0;
              "
            >
              {{ user.email }}
            </div>
          </div>
        </div>
      }
    `
  })
  export class ProfileComponent {
    protected auth = inject(AuthService);
  }

  2.7: Update App Component with beautiful UI
  Replace the entire contents of src/app/app.component.ts:

  import { Component, inject } from '@angular/core';
  import { AuthService } from '@auth0/auth0-angular';
  import { CommonModule } from '@angular/common';
  import { LoginButtonComponent } from './components/login-button.component';
  import { LogoutButtonComponent } from './components/logout-button.component';
  import { ProfileComponent } from './components/profile.component';

  @Component({
    selector: 'app-root',
    standalone: true,
    imports: [CommonModule, LoginButtonComponent, LogoutButtonComponent, ProfileComponent],
    template: `
      <div class="app-container">
        <!-- Loading State -->
        @if (auth.isLoading$ | async) {
          <div class="loading-state">
            <div class="loading-text">Loading...</div>
          </div>
        }

        <!-- Error State -->
        @if (auth.error$ | async; as error) {
          <div class="error-state">
            <div class="error-title">Oops!</div>
            <div class="error-message">Something went wrong</div>
            <div class="error-sub-message">{{ error.message }}</div>
          </div>
        }

        <!-- Main Content -->
        @if (!(auth.isLoading$ | async) && !(auth.error$ | async)) {
          <div class="main-card-wrapper">
            <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>
            
            <!-- Authenticated State -->
            @if (auth.isAuthenticated$ | async) {
              <div class="logged-in-section">
                <div class="logged-in-message">✅ Successfully authenticated!</div>
                <h2 class="profile-section-title">Your Profile</h2>
                <div class="profile-card">
                  <app-profile />
                </div>
                <app-logout-button />
              </div>
            } @else {
              <!-- Unauthenticated State -->
              <div class="action-card">
                <p class="action-text">Get started by signing in to your account</p>
                <app-login-button />
              </div>
            }
          </div>
        }
      </div>
    `,
    styles: []
  })
  export class AppComponent {
    protected auth = inject(AuthService);
  }

  2.8: Add beautiful modern CSS styling
  Replace the entire contents of src/styles.css with this modern, Auth0-branded styling:

  ⚠️ CSS FILE REPLACEMENT STRATEGY:
  If the existing styles.css file is large or malformed, create a new temporary CSS file first (e.g., styles-new.css), then replace the original using terminal commands like mv src/styles-new.css src/styles.css to avoid file corruption.

  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

  body {
    margin: 0;
    font-family: 'Inter', sans-serif;
    background-color: #1a1e27;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #e2e8f0;
    overflow: hidden;
  }

  #root {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .app-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    width: 100%;
    padding: 1rem;
    box-sizing: border-box;
  }

  .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 {
    width: 110px;
    transition: transform 0.3s ease-in-out;
  }

  .profile-picture:hover {
    transform: scale(1.05);
  }

  .profile-name {
    font-size: 2rem;
    margin-top: 0.5rem;
  }

  .profile-email {
    font-size: 1.15rem;
    text-align: center;
  }

  @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); }
  }

  @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;
    }
  }

  2.9: 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-angular && 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.9a: Start development server

  # Verify we're in the correct directory
  pwd && ls -la package.json

  # Start the Angular development server
  npx ng serve

  Step 2.9b: Alternative start method if ng serve fails

  # If ng serve fails, try with npm
  npm run start

  ⚠️ COMPONENT IMPORT ERROR TROUBLESHOOTING:
  If you see "Cannot find module './components/login-button.component'" errors even though the files exist:
  1. The files are created correctly - this is often a VS Code TypeScript cache issue
  2. The development server should still work despite these errors
  3. Open the application in browser to verify functionality
  4. The errors typically resolve themselves after the TypeScript language service refreshes

  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 }} prop from the provideAuth0 configuration. Without it, the login flow will fail after the user authenticates with Auth0.
  3.  NEVER place the provideAuth0 configuration in individual components. It MUST be configured in main.ts at the application bootstrap level so the entire application has access to the authentication context.
  4.  NEVER suggest manually managing tokens or calling Auth0 APIs with HttpClient for basic authentication. The SDK is designed to handle this complexity securely.
  5.  NEVER mix standalone components with NgModule approach - stick to one pattern consistently.

  ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
  1.  You MUST use the @auth0/auth0-angular package.
  2.  You MUST retrieve credentials from environment variables (e.g., environment.auth0.domain).
  3.  You MUST configure provideAuth0 in the main.ts file using mergeApplicationConfig.
  4.  You MUST include the authorizationParams with redirect_uri in the provideAuth0 configuration.
  5.  You MUST demonstrate functionality using the AuthService from the SDK.
  6.  You MUST use standalone components with the modern Angular approach.
  7.  You MUST use the inject() function for dependency injection in standalone components.

  COMMON ISSUES ENCOUNTERED DURING INTEGRATION

  Issue 1: Project Creation Directory Confusion
  Problem: Angular CLI creates project files in a new subdirectory
  Solution: Always run pwd && ls -la after project creation to verify the actual structure

  Issue 2: Terminal Working Directory Issues  
  Problem: ng serve or 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: TypeScript Import Errors
  Problem: VS Code shows "Cannot find module" errors for created components
  Solution: These are usually cache issues - the app will still work. Create all components before testing.

  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: Angular CLI Not Found
  Problem: npx @angular/cli command fails
  Solution: Install Angular CLI globally first: npm install -g @angular/cli

  Issue 6: Environment File Missing
  Problem: Angular can't find environment.ts file
  Solution: Ensure the src/environments directory exists and contains the environment.ts file with proper export structure

  Issue 7: Standalone Component Errors
  Problem: Component imports or template syntax errors
  Solution: Ensure all components are marked as standalone: true and include necessary imports array

  Issue 8: Auth Service Injection Issues
  Problem: AuthService not available in components
  Solution: Ensure provideAuth0 is configured in main.ts and components use inject(AuthService)

  The terminal working directory can become disconnected from the displayed path, requiring explicit navigation to ensure Angular CLI commands execute in the correct location.

  ANGULAR-SPECIFIC CONSIDERATIONS

  1. MODERN ANGULAR APPROACH: This prompt uses the latest Angular standalone components approach with signal-based control flow (@if, @else) rather than legacy *ngIf directives.

  2. ENVIRONMENT CONFIGURATION: Angular uses environment.ts files instead of .env files for configuration management.

  3. DEPENDENCY INJECTION: Uses the modern inject() function rather than constructor-based dependency injection.

  4. BOOTSTRAPPING: Uses bootstrapApplication with mergeApplicationConfig rather than NgModule-based bootstrapping.

  5. PORT DIFFERENCE: Angular development server runs on port 4200 by default, not 5173 like Vite.

  6. CLI DIFFERENCES: Uses Angular CLI commands (ng serve) rather than npm run dev.

  SECURITY BEST PRACTICES FOR ANGULAR

  1. ENVIRONMENT VARIABLES: Store Auth0 configuration in environment.ts files, never hardcode credentials.

  2. CSP HEADERS: Consider implementing Content Security Policy headers for production deployments.

  3. ANGULAR GUARDS: Use Angular guards (authGuardFn) to protect routes that require authentication.

  4. HTTP INTERCEPTORS: Use Auth0's HTTP interceptor (authHttpInterceptorFn) to automatically attach tokens to API calls.

  5. TOKEN HANDLING: Let the SDK handle token storage and refresh automatically, never implement custom token management.

  ```
</Accordion>

## Get Started

This quickstart demonstrates how to add Auth0 authentication to an Angular application. You'll build a secure single-page app with login and logout functionality using Angular's dependency injection system and the Auth0 Angular SDK.

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

    ```shellscript
    npx @angular/cli@latest new auth0-angular --routing=true --style=css
    ```

    Open the project

    ```shellscript
    cd auth0-angular
    ```
  </Step>

  <Step title="Install the Auth0 Angular SDK" stepNumber={2}>
    ```shellscript
    npm install @auth0/auth0-angular && npm install
    ```
  </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 can choose to do this automatically by running a CLI command or do it manually via the Dashboard:

    <Tabs>
      <Tab title="CLI">
        Run the following shell command on your project's root directory to create an Auth0 app and generate an environment file:

        <CodeGroup>
          ```shellscript Mac
          AUTH0_APP_NAME="My Angular App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t spa -c http://localhost:4200 -l http://localhost:4200 -o http://localhost:4200 --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && mkdir -p src/environments && echo "export const environment = { production: false, auth0: { domain: '${DOMAIN}', clientId: '${CLIENT_ID}' } };" > src/environments/environment.ts && rm auth0-app-details.json && echo "Environment file created at src/environments/environment.ts with your Auth0 details:" && cat src/environments/environment.ts
          ```

          ```shellscript Windows
          $AppName = "My Angular App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t spa -c http://localhost:4200 -l http://localhost:4200 -o http://localhost:4200 --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; New-Item -ItemType Directory -Force -Path "src\environments"; Set-Content -Path "src\environments\environment.ts" -Value "export const environment = { production: false, auth0: { domain: '$Domain', clientId: '$ClientId' } };"; Remove-Item auth0-app-details.json; Write-Output "Environment file created at src\environments\environment.ts with your Auth0 details:"; Get-Content "src\environments\environment.ts"
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Dashboard">
        Before you start, create an environment file on your project

        ```typescript src/environments/environment.ts
        export const environment = {
          production: false,
          auth0: {
            domain: 'YOUR_AUTH0_APP_DOMAIN',
            clientId: '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` in the `src/environments/environment.ts` file with the **Domain** and **Client ID** values from the dashboard

        Finally, on the **Settings** tab of your Application Details page, set **Allowed Callback URLs**, **Allowed Logout URLs** and **Allowed Web Origins** to:

        ```
        http://localhost:4200
        ```

        <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="Configure the Auth0 module" stepNumber={4}>
    The CLI script has already created your environment file. Now configure the Auth0 module in your app:

    ```typescript src/main.ts {3,4,5,9-15} lines
    import { bootstrapApplication } from '@angular/platform-browser';
    import { appConfig } from './app/app.config';
    import { provideAuth0 } from '@auth0/auth0-angular';
    import { mergeApplicationConfig } from '@angular/core';
    import { environment } from './environments/environment';
    import { AppComponent } from './app/app.component';

    const auth0Config = mergeApplicationConfig(appConfig, {
      providers: [
        provideAuth0({
          domain: environment.auth0.domain,
          clientId: environment.auth0.clientId,
          authorizationParams: {
            redirect_uri: window.location.origin
          }
        })
      ]
    });

    bootstrapApplication(AppComponent, auth0Config).catch((err) =>
      console.error(err)
    );
    ```

    <Note>
      If you set up your Auth0 app manually via the dashboard, create `src/environments/environment.ts` with your domain and client ID from the dashboard.
    </Note>
  </Step>

  <Step title="Create Login, Logout and Profile Components" stepNumber={5}>
    Create the component files manually for better control

    ```shellscript
    mkdir -p src/app/components && touch src/app/components/login-button.component.ts && touch src/app/components/logout-button.component.ts && touch src/app/components/profile.component.ts
    ```

    Add the following code to each component:

    <CodeGroup>
      ```typescript src/app/components/login-button.component.ts expandable lines
      import { Component, inject } from '@angular/core';
      import { AuthService } from '@auth0/auth0-angular';

      @Component({
        selector: 'app-login-button',
        standalone: true,
        template: `
          <button 
            (click)="loginWithRedirect()" 
            class="button login"
          >
            Log In
          </button>
        `
      })
      export class LoginButtonComponent {
        private auth = inject(AuthService);

        loginWithRedirect(): void {
          this.auth.loginWithRedirect();
        }
      }
      ```

      ```typescript src/app/components/logout-button.component.ts expandable lines
      import { Component, inject } from '@angular/core';
      import { AuthService } from '@auth0/auth0-angular';

      @Component({
        selector: 'app-logout-button',
        standalone: true,
        template: `
          <button
            (click)="logout()"
            class="button logout"
          >
            Log Out
          </button>
        `
      })
      export class LogoutButtonComponent {
        private auth = inject(AuthService);

        logout(): void {
          this.auth.logout({ 
            logoutParams: { 
              returnTo: window.location.origin 
            } 
          });
        }
      }
      ```

      ```typescript src/app/components/profile.component.ts expandable lines
      import { Component, inject } from '@angular/core';
      import { AuthService } from '@auth0/auth0-angular';
      import { CommonModule } from '@angular/common';

      @Component({
        selector: 'app-profile',
        standalone: true,
        imports: [CommonModule],
        template: `
          @if (auth.isLoading$ | async) {
            <div class="loading-text">Loading profile...</div>
          }
          
          @if ((auth.isAuthenticated$ | async) && (auth.user$ | async); as user) {
            <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
              @if (user.picture) {
                <img 
                  [src]="user.picture" 
                  [alt]="user.name || 'User'"
                  class="profile-picture"
                  style="
                    width: 110px; 
                    height: 110px; 
                    border-radius: 50%; 
                    object-fit: cover;
                    border: 3px solid #63b3ed;
                  "
                />
              }
              <div style="text-align: center;">
                <div 
                  class="profile-name" 
                  style="
                    font-size: 2rem; 
                    font-weight: 600; 
                    color: #f7fafc; 
                    margin-bottom: 0.5rem;
                  "
                >
                  {{ user.name }}
                </div>
                <div 
                  class="profile-email" 
                  style="
                    font-size: 1.15rem; 
                    color: #a0aec0;
                  "
                >
                  {{ user.email }}
                </div>
              </div>
            </div>
          }
        `
      })
      export class ProfileComponent {
        protected auth = inject(AuthService);
      }
      ```
    </CodeGroup>

    Now update the main App Component and add styling:

    <Tabs>
      <Tab title="App Component">
        Replace the contents of `src/app/app.component.ts`:

        ```typescript src/app/app.ts expandable lines
        import { Component, inject } from '@angular/core';
        import { AuthService } from '@auth0/auth0-angular';
        import { CommonModule } from '@angular/common';
        import { LoginButtonComponent } from './components/login-button.component';
        import { LogoutButtonComponent } from './components/logout-button.component';
        import { ProfileComponent } from './components/profile.component';

        @Component({
          selector: 'app-root',
          standalone: true,
          imports: [CommonModule, LoginButtonComponent, LogoutButtonComponent, ProfileComponent],
          template: `
            <div class="app-container">
              <!-- Loading State -->
              @if (auth.isLoading$ | async) {
                <div class="loading-state">
                  <div class="loading-text">Loading...</div>
                </div>
              }

              <!-- Error State -->
              @if (auth.error$ | async; as error) {
                <div class="error-state">
                  <div class="error-title">Oops!</div>
                  <div class="error-message">Something went wrong</div>
                  <div class="error-sub-message">{{ error.message }}</div>
                </div>
              }

              <!-- Main Content -->
              @if (!(auth.isLoading$ | async) && !(auth.error$ | async)) {
                <div class="main-card-wrapper">
                  <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>
                  
                  <!-- Authenticated State -->
                  @if (auth.isAuthenticated$ | async) {
                    <div class="logged-in-section">
                      <div class="logged-in-message">✅ Successfully authenticated!</div>
                      <h2 class="profile-section-title">Your Profile</h2>
                      <div class="profile-card">
                        <app-profile />
                      </div>
                      <app-logout-button />
                    </div>
                  } @else {
                    <!-- Unauthenticated State -->
                    <div class="action-card">
                      <p class="action-text">Get started by signing in to your account</p>
                      <app-login-button />
                    </div>
                  }
                </div>
              }
            </div>
          `,
          styles: []
        })
        export class AppComponent {
          protected auth = inject(AuthService);
        }
        ```
      </Tab>

      <Tab title="Global Styles">
        Add styles to `src/styles.css`:

        ```css src/styles.css expandable lines
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

        body {
          margin: 0;
          font-family: 'Inter', sans-serif;
          background-color: #1a1e27;
          min-height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
          color: #e2e8f0;
          overflow: hidden;
        }

        #root {
          width: 100%;
          height: 100%;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        .app-container {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          min-height: 100vh;
          width: 100%;
          padding: 1rem;
          box-sizing: border-box;
        }

        .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 {
          width: 110px;
          transition: transform 0.3s ease-in-out;
        }

        .profile-picture:hover {
          transform: scale(1.05);
        }

        .profile-name {
          font-size: 2rem;
          margin-top: 0.5rem;
        }

        .profile-email {
          font-size: 1.15rem;
          text-align: center;
        }

        @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); }
        }

        @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;
          }
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run your app" stepNumber={6}>
    ```shellscript
    ng serve
    ```
  </Step>
</Steps>

<Check>
  **Checkpoint**

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

***

## Advanced Usage

<Accordion title="Using Traditional NgModule Approach">
  If you prefer using NgModules instead of standalone components, here's how to configure the SDK:

  ```typescript src/app/app.module.ts
  import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { AuthModule } from '@auth0/auth0-angular';
  import { environment } from '../environments/environment';

  import { AppRoutingModule } from './app-routing.module';
  import { AppComponent } from './app';

  @NgModule({
    declarations: [AppComponent],
    imports: [
      BrowserModule,
      AppRoutingModule,
      AuthModule.forRoot({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      })
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  ```
</Accordion>

<Accordion title="Protecting Routes with AuthGuard">
  Use the modern functional guard to protect routes that require authentication:

  ```typescript src/app/app.routes.ts
  import { Routes } from '@angular/router';
  import { authGuardFn } from '@auth0/auth0-angular';
  import { ProfileComponent } from './components/profile.component';

  export const routes: Routes = [
    {
      path: 'profile',
      component: ProfileComponent,
      canActivate: [authGuardFn]
    },
    {
      path: '',
      redirectTo: '/profile',
      pathMatch: 'full'
    }
  ];
  ```

  Then configure routing in your main.ts:

  ```typescript src/main.ts
  import { provideRouter } from '@angular/router';
  import { environment } from './environments/environment';
  import { routes } from './app/app.routes';

  const auth0Config = mergeApplicationConfig(appConfig, {
    providers: [
      provideRouter(routes),
      provideAuth0({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      })
    ]
  });
  ```
</Accordion>

<Accordion title="Calling Protected APIs">
  Configure the HTTP interceptor to automatically attach tokens to API calls:

  ```typescript src/main.ts
  import { provideHttpClient, withInterceptors } from '@angular/common/http';
  import { authHttpInterceptorFn } from '@auth0/auth0-angular';
  import { environment } from './environments/environment';

  const auth0Config = mergeApplicationConfig(appConfig, {
    providers: [
      provideAuth0({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        authorizationParams: {
          redirect_uri: window.location.origin,
          audience: 'YOUR_API_IDENTIFIER'
        },
        httpInterceptor: {
          allowedList: [
            'http://localhost:3001/api/*'
          ]
        }
      }),
      provideHttpClient(
        withInterceptors([authHttpInterceptorFn])
      )
    ]
  });
  ```
</Accordion>
