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

# Add Login to Your Angular Application

> This guide demonstrates how to integrate Auth0, add authentication, and display user profile information in any Angular application using the Auth0 Angular SDK.

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="Use AI to integrate Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).

  **Install:**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-angular
  ```

  **Then ask your AI assistant:**

  ```text theme={null}
  Add Auth0 authentication to my Angular app
  ```

  Your AI assistant will automatically create your Auth0 application, fetch credentials, install `@auth0/auth0-angular`, create route guards and HTTP interceptors, and configure your environment. [Full agent skills documentation →](/docs/quickstart/agent-skills)
</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+
  * **[jq](https://jqlang.org/)** - Required for Auth0 CLI setup

  Verify installation: `node --version && npm --version`

  **Angular Version Compatibility:** This quickstart works with **Angular 19 through 21** using the Angular CLI. The `@auth0/auth0-angular` SDK supports Angular 13 and newer.
</Note>

## 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.

export const localEnvSnippet = `export const environment = {
  production: false,
  auth0: {
    domain: {yourDomain},
    clientId: {yourClientId}
  }
};`;

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

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

    Open the project

    ```shellscript theme={null}
    cd auth0-angular
    ```
  </Step>

  <Step title="Install the Auth0 Angular SDK" stepNumber={2}>
    ```shellscript theme={null}
    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 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="Angular" appType="spa" allowedCallbackUrls={["http://localhost:4200"]} allowedLogoutUrls={["http://localhost:4200"]} allowedOriginUrls={["http://localhost:4200"]} />

        <AuthCodeBlock children={localEnvSnippet} language="typescript" filename="src/environments/environment.ts" />
      </Tab>

      <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 theme={null}
          # Install Auth0 CLI (if not already installed)
          brew tap auth0/auth0-cli && brew install auth0

          # Set up Auth0 app and generate environment file
          auth0 qs setup --app --type spa --framework angular --name "My Angular App" --port 4200
          ```

          ```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 environment file
          auth0 qs setup --app --type spa --framework angular --name "My Angular App" --port 4200
          ```
        </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:4200`
          3. Generate `src/environments/environment.ts` with your Auth0 domain and client ID
        </Note>
      </Tab>

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

        ```typescript src/environments/environment.ts theme={null}
        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, configure the following URLs:

        **Allowed Callback URLs:**

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

        **Allowed Logout URLs:**

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

        **Allowed Web Origins:**

        ```
        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}>
    With your environment file in place from the previous step, add `provideAuth0` to the providers array in your `app.config.ts`:

    ```typescript src/app/app.config.ts {3,4,5,11-17} lines theme={null}
    import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
    import { provideRouter } from '@angular/router';
    import { provideAuth0 } from '@auth0/auth0-angular';
    import { environment } from '../environments/environment';
    import { routes } from './app.routes';

    export const appConfig: ApplicationConfig = {
      providers: [
        provideZoneChangeDetection({ eventCoalescing: true }),
        provideRouter(routes),
        provideAuth0({
          domain: environment.auth0.domain,
          clientId: environment.auth0.clientId,
          authorizationParams: {
            redirect_uri: window.location.origin
          }
        })
      ]
    };
    ```

    <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.

      Angular 20+ projects also include `provideBrowserGlobalErrorListeners()` in this file — keep it in the array alongside `provideAuth0`. No changes to `main.ts` are needed.
    </Note>
  </Step>

  <Step title="Create Login, Logout and Profile Components" stepNumber={5}>
    Use the Angular CLI to scaffold the component files:

    ```shellscript theme={null}
    ng generate component components/login-button --inline-template --inline-style --skip-tests && \
    ng generate component components/logout-button --inline-template --inline-style --skip-tests && \
    ng generate component components/profile --inline-template --inline-style --skip-tests
    ```

    Add the following code to each component:

    <AuthCodeGroup>
      ```typescript src/app/components/login-button.component.ts expandable lines theme={null}
      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 theme={null}
      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 theme={null}
      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);
      }
      ```
    </AuthCodeGroup>

    Now update the main App Component and add styling:

    <Tabs>
      <Tab title="App Component">
        Replace the contents of your app component file (`src/app/app.ts` on Angular 20+, or `src/app/app.component.ts` on Angular 19):

        ```typescript src/app/app.ts expandable lines theme={null}
        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 App {
          protected auth = inject(AuthService);
        }
        ```
      </Tab>

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

        ```css src/styles.css expandable lines theme={null}
        @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 theme={null}
    ng serve
    ```

    <Info>
      If port 4200 is in use, run: `ng serve --port 4201` and update your Auth0 app's callback URLs to `http://localhost:4201`
    </Info>
  </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 created your project with `--standalone=false` or prefer using NgModules instead of standalone components, here's how to configure the SDK with Angular 20+ CLI-generated projects:

  ```typescript src/main.ts theme={null}
  import { platformBrowser } from '@angular/platform-browser';
  import { AppModule } from './app/app-module';

  platformBrowser().bootstrapModule(AppModule)
    .catch((err) => console.error(err));
  ```

  ```typescript src/app/app-module.ts theme={null}
  import { NgModule, provideBrowserGlobalErrorListeners } 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 { App } from './app';

  @NgModule({
    declarations: [App],
    imports: [
      BrowserModule,
      AppRoutingModule,
      AuthModule.forRoot({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      })
    ],
    providers: [provideBrowserGlobalErrorListeners()],
    bootstrap: [App]
  })
  export class AppModule { }
  ```

  <Note>
    If you're using **Angular 19**, your generated files are typically `app.component.ts`, `app.module.ts`, and `app-routing.module.ts`, and `main.ts` uses `platformBrowserDynamic` instead of `platformBrowser`.

    **Angular 20+** generates `app.ts`, `app-module.ts`, and `app-routing-module.ts` (no dots in filenames), and `main.ts` uses `platformBrowser` as shown above.

    In all cases, NgModule projects bootstrap via `bootstrapModule()` rather than the `bootstrapApplication()` approach shown in the main quickstart.
  </Note>
</Accordion>

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

  ```typescript src/app/app.routes.ts theme={null}
  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 add `provideAuth0` and the router to your `app.config.ts` (if you haven't already from Step 4):

  ```typescript src/app/app.config.ts theme={null}
  import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
  import { provideRouter } from '@angular/router';
  import { provideAuth0 } from '@auth0/auth0-angular';
  import { environment } from '../environments/environment';
  import { routes } from './app.routes';

  export const appConfig: ApplicationConfig = {
    providers: [
      provideZoneChangeDetection({ eventCoalescing: true }),
      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. Add `provideHttpClient` with the Auth0 interceptor and an `audience` to your `app.config.ts`:

  ```typescript src/app/app.config.ts theme={null}
  import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
  import { provideRouter } from '@angular/router';
  import { provideHttpClient, withInterceptors } from '@angular/common/http';
  import { provideAuth0, authHttpInterceptorFn } from '@auth0/auth0-angular';
  import { environment } from '../environments/environment';
  import { routes } from './app.routes';

  export const appConfig: ApplicationConfig = {
    providers: [
      provideZoneChangeDetection({ eventCoalescing: true }),
      provideRouter(routes),
      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>
