## Use AI to integrate Auth0

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

**Install:**

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

**Then ask your AI assistant:**

```
Add Auth0 authentication to my 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 →](/content/docs/quickstart/agent-skills/index.html)

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

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

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

1. Create a new project

Create a new Angular project for this Quickstart

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

Open the project

```
    cd auth0-angular
    ```

2. Install the Auth0 Angular SDK

```
    npm install @auth0/auth0-angular && npm install
    ```

3. Setup your Auth0 App

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

- Quick Setup (recommended)
    - CLI
    - Dashboard

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

Log into create the app

```
src/environments/environment.ts
    export const environment = {
      production: false,
      auth0: {
        domain: {yourDomain},
        clientId: {yourClientId}
      }
    };
    ```

Run the following shell command on your project’s root directory to create an Auth0 app and generate an environment file:

**Mac**
    ```
    # 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
    ```

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

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

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

Before you start, create an environment file on your project

```
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, configure the following URLs:

**Allowed Callback URLs:**
    ```
    http://localhost:4200
    ```

**Allowed Logout URLs:**
    ```
    http://localhost:4200
    ```

**Allowed Web Origins:**
    ```
    http://localhost:4200
    ```

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

4. Configure the Auth0 module

With your environment file in place from the previous step, add `provideAuth0` to the providers array in your `app.config.ts`:

```
src/app/app.config.ts
    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
          }
        })
      ]
    };
    ```

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.

5. Create Login, Logout and Profile Components

Use the Angular CLI to scaffold the component files:
    
    ```
    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:
    
    `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();
      }
    }
    ```
    
    `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
          }
        });
      }
    }
    ```
    
    `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);
    }
    ```

Now update the main App Component and add styling:

- App Component
    - Global Styles

Replace the contents of your app component file (`src/app/app.ts` on Angular 20+, or `src/app/app.component.ts` on Angular 19):

`src/app/app.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 App {
      protected auth = inject(AuthService);
    }
    ```

Add styles to `src/styles.css`:
    ```
    @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;
      }
    }
    ```

6. Run your app

```
    ng serve
    ```

If port 4200 is in use, run: `ng serve --port 4201` and update your Auth0 app’s callback URLs to `http://localhost:4201`

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

## Advanced Usage

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

`src/main.ts`
```javascript
import { platformBrowser } from '@angular/platform-browser';
import { AppModule } from './app/app-module';
platformBrowser().bootstrapModule(AppModule)
  .catch((err) => console.error(err));
```

`src/app/app-module.ts`
```javascript
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 { }
```

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.

### Protecting Routes with AuthGuard

Use the modern functional guard to protect routes that require authentication:

`src/app/app.routes.ts`
```javascript
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):

`src/app/app.config.ts`
```javascript
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,
        audience: 'YOUR_API_IDENTIFIER'
      },
      httpInterceptor: {
        allowedList: [
          'http://localhost:3001/api/*'
        ]
      }
    })
  ]
};
```
