← Files Auth0ARCHIVED FILE
skills/auth0/references/framework-angular/index.md
23.3 KB · Sep 30, 2026 · 23:15 UTC
# Auth0 Angular Integration
Add authentication to Angular applications using @auth0/auth0-angular.
## Prerequisites
- Angular 13+ application
- Auth0 account and application configured
- If Auth0 isn't set up yet, set it up first with the Auth0 CLI (`auth0 login`, then `auth0 apps create`)
## When NOT to Use
- **AngularJS (1.x)** - This SDK requires Angular 13+, use legacy solutions for AngularJS
- **Mobile applications** - Use the Auth0 integration workflow for React Native, or native SDKs for Ionic
- **Backend APIs** - Use JWT validation middleware for your server language
## Quick Start Workflow
### 1. Install SDK
```bash
npm install @auth0/auth0-angular
```
### 2. Configure Environment
**For automated setup with Auth0 CLI**, see the Setup Guide section below for complete scripts.
**For manual setup:**
Update `src/environments/environment.ts`:
```typescript
export const environment = {
production: false,
auth0: {
domain: 'your-tenant.auth0.com',
clientId: 'your-client-id',
authorizationParams: {
redirect_uri: window.location.origin
}
}
};
```
### 3. Configure Auth Module
**For standalone components (Angular 14+):**
Update `src/app/app.config.ts`:
```typescript
import { ApplicationConfig } from '@angular/core';
import { provideAuth0 } from '@auth0/auth0-angular';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideAuth0({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: environment.auth0.authorizationParams
})
]
};
```
**For NgModule-based apps:**
Update `src/app/app.module.ts`:
```typescript
import { AuthModule } from '@auth0/auth0-angular';
import { environment } from '../environments/environment';
@NgModule({
imports: [
AuthModule.forRoot({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: environment.auth0.authorizationParams
})
]
})
export class AppModule {}
```
### 4. Add Authentication UI
Update `src/app/app.component.ts`:
```typescript
import { Component } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
@Component({
selector: 'app-root',
template: `
<div *ngIf="auth.isLoading$ | async; else loaded">
<p>Loading...</p>
</div>
<ng-template #loaded>
<ng-container *ngIf="auth.isAuthenticated$ | async; else loggedOut">
<div *ngIf="auth.user$ | async as user">
<img [src]="user.picture" [alt]="user.name" />
<h2>Welcome, {{ user.name }}!</h2>
<button (click)="logout()">Logout</button>
</div>
</ng-container>
<ng-template #loggedOut">
<button (click)="login()">Login</button>
</ng-template>
</ng-template>
`
})
export class AppComponent {
constructor(public auth: AuthService) {}
login(): void {
this.auth.loginWithRedirect();
}
logout(): void {
this.auth.logout({ logoutParams: { returnTo: window.location.origin } });
}
}
```
### 5. Test Authentication
Start your dev server and test the login flow:
```bash
ng serve
```
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| Forgot to add redirect URI in Auth0 Dashboard | Add your application URL (e.g., `http://localhost:4200`, `https://app.example.com`) to Allowed Callback URLs in Auth0 Dashboard |
| Not configuring AuthModule properly | Must call `AuthModule.forRoot()` in NgModule or `provideAuth0()` in standalone config |
| Accessing auth before initialization | Use `isLoading$` observable to wait for SDK initialization |
| Storing tokens manually | Never manually store tokens - SDK handles secure storage automatically |
| No token sent to API | Use either `authHttpInterceptorFn` for automatic token attachment, or `getAccessTokenSilently()` for manual control — see the Calling a Protected API section below |
| Route guard not protecting routes | Apply `AuthGuard` (or `authGuardFn`) to protected routes in routing config |
## Related Capabilities
- Auth0 setup — run the CLI (`auth0 login`, then `auth0 apps create`)
- Migrating from another auth provider → ask for migration (migrate)
- Multi-factor authentication → ask for MFA (feature:mfa)
- Managing Auth0 resources from the terminal → the Auth0 CLI (`tooling-cli`)
## Quick Reference
**Core Services:**
- `AuthService` - Main authentication service
- `isAuthenticated$` - Observable check if user is logged in
- `user$` - Observable user profile information
- `loginWithRedirect()` - Initiate login
- `logout()` - Log out user
- `getAccessTokenSilently()` - Get access token manually (alternative to HTTP interceptor)
**Common Use Cases:**
- Login/Logout buttons → See Step 4 above
- Protected routes with guards → see the Protected Routes section below
- Calling a protected API → see the Calling a Protected API section below
- Error handling → see the Error Handling section below
## References
- [Auth0 Angular SDK Documentation](https://auth0.com/docs/libraries/auth0-angular)
- [Auth0 Angular Quickstart](https://auth0.com/docs/quickstart/spa/angular)
- [SDK GitHub Repository](https://github.com/auth0/auth0-angular)
---
## Common Patterns
### Protected Route with Auth Guard
Create an auth guard (`src/app/auth.guard.ts`):
```typescript
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '@auth0/auth0-angular';
import { map, take } from 'rxjs/operators';
export const authGuard = () => {
const auth = inject(AuthService);
const router = inject(Router);
return auth.isAuthenticated$.pipe(
take(1),
map(isAuthenticated => {
if (!isAuthenticated) {
auth.loginWithRedirect();
return false;
}
return true;
})
);
};
```
**Configure routes** (`src/app/app.routes.ts`):
```typescript
import { Routes } from '@angular/router';
import { authGuard } from './auth.guard';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'profile',
component: ProfileComponent,
canActivate: [authGuard] // Protect this route
}
];
```
---
### Get User Profile Component
Create `src/app/profile/profile.component.ts`:
```typescript
import { Component } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-profile',
standalone: true,
imports: [CommonModule],
template: `
<div *ngIf="auth.user$ | async as user">
<h1>Profile</h1>
<img [src]="user.picture" [alt]="user.name" />
<p>Name: {{ user.name }}</p>
<p>Email: {{ user.email }}</p>
<p>User ID: {{ user.sub }}</p>
</div>
`
})
export class ProfileComponent {
constructor(public auth: AuthService) {}
}
```
---
### Call Protected API (Manual Token Approach)
This example uses `getAccessTokenSilently()` to manually obtain and attach tokens. This is an alternative to using the built-in HTTP interceptor — see the Calling a Protected API section for both approaches.
Create `src/app/api-test/api-test.component.ts`:
```typescript
import { Component } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { HttpClient } from '@angular/common/http';
import { switchMap } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-api-test',
standalone: true,
imports: [CommonModule],
template: `
<div>
<button (click)="callApi()">Call API</button>
<div *ngIf="error">Error: {{ error }}</div>
<pre *ngIf="data">{{ data | json }}</pre>
</div>
`
})
export class ApiTestComponent {
data: any = null;
error: string | null = null;
constructor(
private auth: AuthService,
private http: HttpClient
) {}
callApi(): void {
this.auth.getAccessTokenSilently({
authorizationParams: {
audience: 'https://your-api-identifier'
}
}).pipe(
switchMap(token =>
this.http.get('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${token}`
}
})
)
).subscribe({
next: (response) => {
this.data = response;
},
error: (err) => {
this.error = err.message;
}
});
}
}
```
**Note:** If calling APIs, add `audience` to your Auth module configuration:
```typescript
AuthModule.forRoot({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: {
redirect_uri: window.location.origin,
audience: 'https://your-api-identifier' // Add this
}
})
```
---
### Custom HTTP Interceptor for API Calls
This shows how to build a custom interceptor from scratch. In most cases, you should use the SDK's built-in `authHttpInterceptorFn` instead — see the Calling a Protected API section. A custom interceptor is only needed when you require logic beyond what `allowedList` provides.
Create `src/app/auth.interceptor.ts`:
```typescript
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { switchMap } from 'rxjs/operators';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
// Only add token to API calls
if (req.url.startsWith('https://api.example.com')) {
return auth.getAccessTokenSilently().pipe(
switchMap(token => {
const clonedReq = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(clonedReq);
})
);
}
return next(req);
};
```
**Register interceptor** (`src/app/app.config.ts`):
```typescript
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideAuth0({...}),
provideHttpClient(
withInterceptors([authInterceptor])
)
]
};
```
---
## Configuration Options
### Complete Auth Configuration
```typescript
AuthModule.forRoot({
domain: 'your-tenant.auth0.com',
clientId: 'your-client-id',
authorizationParams: {
redirect_uri: window.location.origin,
audience: 'https://your-api-identifier', // For API calls
scope: 'openid profile email', // Default scopes
},
cacheLocation: 'localstorage', // or 'memory'
useRefreshTokens: true, // Enable refresh tokens
skipRedirectCallback: false, // Skip automatic callback handling
errorPath: '/error', // Path to redirect on auth errors (default: '/')
httpInterceptor: {
allowedList: [
'https://api.example.com/*' // Automatically add tokens to these URLs
]
}
})
```
---
## Testing
1. Start your dev server: `ng serve`
2. Navigate to `http://localhost:4200`
3. Click "Login" button
4. Complete Auth0 Universal Login
5. Verify redirect back with user authenticated
6. Test protected routes
7. Click "Logout" and verify user is logged out
---
## Common Issues
| Issue | Solution |
|-------|----------|
| "Invalid state" error | Clear browser storage. Ensure `redirect_uri` matches configured callback URL |
| User stuck on loading | Check Auth0 application has `http://localhost:4200` in callback URLs |
| API calls fail with 401 | Ensure `audience` is configured and matches your API identifier |
| Logout doesn't work | Include `returnTo` URL and configure in Auth0 "Allowed Logout URLs" |
| HTTP interceptor not working | Check `allowedList` includes your API URLs |
---
## Security Considerations
- **Never expose client secret** - Angular is client-side, use only public client credentials
- **Use PKCE** - Enabled by default with @auth0/auth0-angular
- **Validate tokens on backend** - Never trust client-side token validation
- **Use HTTPS in production** - Auth0 requires HTTPS for production redirect URLs
- **Implement proper CORS** - Configure allowed origins in Auth0 application settings
---
## Advanced Methods
### getAccessTokenWithPopup
Gets an access token via popup window. Useful when silent authentication fails (e.g., third-party cookies blocked).
```typescript
// Try silent, fall back to popup
this.auth.getAccessTokenSilently().subscribe({
next: (token) => {
// Use the token (e.g., attach to API requests)
},
error: () => {
// Silent auth failed, try popup
this.auth.getAccessTokenWithPopup().subscribe(token => {
// Use the token (e.g., attach to API requests)
});
}
});
```
### connectAccountWithRedirect
Redirects to connect an additional account to the logged-in user. Allows users to link multiple identity providers.
```typescript
// Link a Google account to existing user
this.auth.connectAccountWithRedirect({
connection: 'google-oauth2',
scopes: ['openid', 'profile', 'email'],
authorizationParams: {
// additional params
}
}).subscribe();
```
After the redirect callback, `handleRedirectCallback` will be called with the details of the connected account.
---
## Related Capabilities
- Auth0 setup — run the CLI (`auth0 login`, then `auth0 apps create`)
- Migrating from another auth provider → ask for migration (migrate)
- Multi-factor authentication → ask for MFA (feature:mfa)
- B2B multi-tenancy → ask for Organizations (feature:organizations)
- Passkey authentication → ask for MFA (feature:mfa)
---
## References
- [Auth0 Angular SDK Documentation](https://auth0.com/docs/libraries/auth0-angular)
- [Auth0 Angular SDK GitHub](https://github.com/auth0/auth0-angular)
- [Auth0 Angular Quickstart](https://auth0.com/docs/quickstart/spa/angular)
- [Angular Router Documentation](https://angular.io/guide/router)
---
# Auth0 Angular Integration Patterns
Angular-specific implementation patterns with route guards, HTTP interceptors, and RxJS.
---
## Protected Routes
### Auth Guard
Create `src/app/guards/auth.guard.ts`:
```typescript
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '@auth0/auth0-angular';
import { map } from 'rxjs/operators';
export const authGuard = () => {
const authService = inject(AuthService);
const router = inject(Router);
return authService.isAuthenticated$.pipe(
map(isAuthenticated => {
if (!isAuthenticated) {
authService.loginWithRedirect();
return false;
}
return true;
})
);
};
```
### Apply Guard to Routes
```typescript
// app.routes.ts (standalone)
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'profile',
component: ProfileComponent,
canActivate: [authGuard]
}
];
```
---
## Calling a Protected API
There are two alternative approaches to attach access tokens to API requests. Choose the one that best fits your needs — you do not need both:
- **HTTP Interceptor (recommended)** — Automatically attaches tokens to outgoing requests matching a configured URL list. This is the simplest, most centralized approach and works well for most applications.
- **Manual token retrieval** — Call `getAccessTokenSilently()` to obtain a token and attach it to requests yourself. Use this when you need explicit, per-request control over token handling.
### Option 1: HTTP Interceptor
Configure the built-in HTTP interceptor in app config:
```typescript
// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authHttpInterceptorFn } from '@auth0/auth0-angular';
import { environment } from '../environments/environment'; // Adjust path as needed
export const appConfig: ApplicationConfig = {
providers: [
provideAuth0({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: {
audience: 'https://your-api-identifier',
redirect_uri: window.location.origin
},
httpInterceptor: {
allowedList: [
'/api/*',
'https://api.example.com/*'
]
}
}),
provideHttpClient(
withInterceptors([authHttpInterceptorFn])
)
]
};
```
With this in place, any `HttpClient` request to a URL matching `allowedList` will automatically include the access token:
```typescript
// data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class DataService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get('https://api.example.com/data');
// Access token automatically added by interceptor
}
}
```
### Option 2: Manual Token Retrieval
If you prefer explicit control instead of using the interceptor, call `getAccessTokenSilently()` to obtain a token and attach it yourself:
```typescript
import { AuthService } from '@auth0/auth0-angular';
import { HttpClient } from '@angular/common/http';
import { switchMap } from 'rxjs/operators';
constructor(private auth: AuthService, private http: HttpClient) {}
callApi() {
this.auth.getAccessTokenSilently({
authorizationParams: {
audience: 'https://your-api-identifier'
}
}).pipe(
switchMap(token =>
this.http.get('https://api.example.com/data', {
headers: { Authorization: `Bearer ${token}` }
})
)
).subscribe({
next: (response) => console.log(response),
error: (err) => console.error(err)
});
}
```
---
## User Profile Component
```typescript
import { Component } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-profile',
standalone: true,
imports: [CommonModule],
template: `
<div *ngIf="auth.user$ | async as user">
<img [src]="user.picture" [alt]="user.name" />
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
<pre>{{ user | json }}</pre>
</div>
`
})
export class ProfileComponent {
constructor(public auth: AuthService) {}
}
```
---
## Error Handling
### Handle Auth Errors
```typescript
import { Component, OnInit } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
@Component({
template: `
<div *ngIf="error$ | async as error" class="error">
<h3>Authentication Error</h3>
<p>{{ error.message }}</p>
</div>
`
})
export class AppComponent implements OnInit {
error$ = this.auth.error$;
constructor(private auth: AuthService) {}
ngOnInit() {
this.error$.subscribe(error => {
if (error) {
console.error('Auth error:', error);
}
});
}
}
```
---
## Common Patterns
### Login with Options
```typescript
login() {
this.auth.loginWithRedirect({
authorizationParams: {
connection: 'google-oauth2',
screen_hint: 'signup'
}
});
}
```
## Testing
### Mock AuthService
```typescript
// auth.service.mock.ts
import { of } from 'rxjs';
export const mockAuthService = {
isAuthenticated$: of(true),
user$: of({ name: 'Test User', email: 'test@example.com' }),
loginWithRedirect: jasmine.createSpy('loginWithRedirect'),
logout: jasmine.createSpy('logout'),
getAccessTokenSilently: jasmine.createSpy('getAccessTokenSilently').and.returnValue(of('mock-token'))
};
```
### Use in Tests
```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AuthService } from '@auth0/auth0-angular';
import { mockAuthService } from './auth.service.mock';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: AuthService, useValue: mockAuthService }
]
});
fixture = TestBed.createComponent(AppComponent);
});
it('should display user name', () => {
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('Test User');
});
});
```
---
## Common Issues
| Issue | Solution |
|-------|----------|
| CORS errors | Add URLs to "Allowed Web Origins" in Auth0 Dashboard |
| Interceptor not adding tokens | Verify `allowedList` in httpInterceptor config |
| Guard not redirecting | Ensure AuthService is provided in root |
| Observables not updating | Use `async` pipe or subscribe properly |
---
---
# Auth0 Angular Setup Guide
Complete setup instructions for Angular applications.
---
## Quick Setup (Automated)
### Bash Script
```bash
#!/bin/bash
# Install Auth0 CLI
if ! command -v auth0 &> /dev/null; then
if [[ "$OSTYPE" == "darwin"* ]]; then
brew install auth0
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
# Download and review the install script before executing
curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh -o /tmp/auth0-install.sh
echo "⚠️ Review the install script at /tmp/auth0-install.sh before running"
sh /tmp/auth0-install.sh -b /usr/local/bin
rm /tmp/auth0-install.sh
fi
fi
# Login to Auth0
if ! auth0 tenants list &> /dev/null; then
echo "Auth0 Login Required"
read -p "Do you have an Auth0 account? (y/n): " HAS_ACCOUNT
if [[ "$HAS_ACCOUNT" != "y" ]]; then
echo "Visit https://auth0.com/signup to create an account"
read -p "Press Enter when ready..."
fi
auth0 login
fi
# Create or select app
auth0 apps list
read -p "Enter your Auth0 app ID (or press Enter to create new): " APP_ID
if [ -z "$APP_ID" ]; then
APP_NAME="${PWD##*/}-angular-app"
APP_ID=$(auth0 apps create \
--name "$APP_NAME" \
--type spa \
--auth-method None \
--callbacks "http://localhost:4200" \
--logout-urls "http://localhost:4200" \
--origins "http://localhost:4200" \
--web-origins "http://localhost:4200" \
--metadata "created_by=agent_skills" \
--json | grep -o '"client_id":"[^"]*' | cut -d'"' -f4)
fi
# Get credentials
AUTH0_DOMAIN=$(auth0 apps show "$APP_ID" --json | grep -o '"domain":"[^"]*' | cut -d'"' -f4)
AUTH0_CLIENT_ID=$(auth0 apps show "$APP_ID" --json | grep -o '"client_id":"[^"]*' | cut -d'"' -f4)
echo "✅ Configuration complete!"
echo "Update src/environments/environment.ts with:"
echo " domain: '$AUTH0_DOMAIN'"
echo " clientId: '$AUTH0_CLIENT_ID'"
```
---
## Manual Setup
### Step 1: Install SDK
```bash
npm install @auth0/auth0-angular
```
### Step 2: Configure Environment
Create or update `src/environments/environment.ts`:
```typescript
export const environment = {
production: false,
auth0: {
domain: 'your-tenant.auth0.com',
clientId: 'your-client-id',
authorizationParams: {
redirect_uri: window.location.origin
}
}
};
```
For production (`src/environments/environment.prod.ts`):
```typescript
export const environment = {
production: true,
auth0: {
domain: 'your-tenant.auth0.com',
clientId: 'your-client-id',
authorizationParams: {
redirect_uri: 'https://app.example.com'
}
}
};
```
### Step 3: Get Auth0 Credentials
Using Auth0 CLI:
```bash
auth0 login
auth0 apps list
auth0 apps show <app-id>
```
Or via [Auth0 Dashboard](https://manage.auth0.com):
1. Create Single Page Application
2. Configure callback URLs: `http://localhost:4200`
3. Copy domain and client ID
---
## Troubleshooting
**Module not found errors:**
- Ensure @auth0/auth0-angular is in package.json
- Run `npm install`
**CORS errors:**
- Add `http://localhost:4200` to "Allowed Web Origins" in Auth0 Dashboard
**Environment variables not working:**
- Angular uses environment files, not .env
- Rebuild app after changing environment files
---
SHA-256: 1e4daa8545c9cce05b1ac8706114278be38d21ab28c4eb598ba1787a98e44cbc