Auth0 integration
Integrate Auth0 authentication into your Aurelia 2 application using the modern Auth0 SPA SDK.
Prerequisites
Auth0 account with configured application
Install the Auth0 SPA SDK:
npm install @auth0/auth0-spa-js
Environment Configuration
Store Auth0 configuration securely:
// src/environment.ts
export const environment = {
auth0: {
domain: process.env.AUTH0_DOMAIN!,
clientId: process.env.AUTH0_CLIENT_ID!,
redirectUri: window.location.origin,
// Additional scopes for your application
scope: 'openid profile email'
}
};
Auth Service
// src/services/auth.ts
import { DI, Registration } from '@aurelia/kernel';
import { createAuth0Client, Auth0Client, User } from '@auth0/auth0-spa-js';
import { environment } from '../environment';
export const IAuthService = DI.createInterface<IAuthService>('IAuthService');
export interface IAuthService {
isAuthenticated(): Promise<boolean>;
getUser(): Promise<User | undefined>;
login(): Promise<void>;
logout(): void;
handleRedirectCallback(): Promise<void>;
getAccessToken(): Promise<string>;
}
export class AuthService implements IAuthService {
private auth0Client?: Auth0Client;
async initialize(): Promise<void> {
if (this.auth0Client) return;
this.auth0Client = await createAuth0Client({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: {
redirect_uri: environment.auth0.redirectUri,
scope: environment.auth0.scope
},
useRefreshTokens: true,
cacheLocation: 'localstorage'
});
}
async login(): Promise<void> {
await this.ensureInitialized();
await this.auth0Client!.loginWithRedirect();
}
async handleRedirectCallback(): Promise<void> {
await this.ensureInitialized();
const query = window.location.search;
if (query.includes('code=') && query.includes('state=')) {
await this.auth0Client!.handleRedirectCallback();
window.history.replaceState({}, document.title, window.location.pathname);
}
}
async isAuthenticated(): Promise<boolean> {
await this.ensureInitialized();
return this.auth0Client!.isAuthenticated();
}
async getUser(): Promise<User | undefined> {
await this.ensureInitialized();
return this.auth0Client!.getUser();
}
async getAccessToken(): Promise<string> {
await this.ensureInitialized();
return this.auth0Client!.getTokenSilently();
}
logout(): void {
this.auth0Client?.logout({
logoutParams: {
returnTo: window.location.origin
}
});
}
private async ensureInitialized(): Promise<void> {
if (!this.auth0Client) {
await this.initialize();
}
}
}
export const AuthServiceRegistration = Registration.singleton(IAuthService, AuthService);
Application Setup
Register the service and initialize Auth0:
// src/main.ts
import { Aurelia, StandardConfiguration, AppTask } from '@aurelia/runtime-html';
import { AuthServiceRegistration, IAuthService } from './services/auth';
import { resolve } from '@aurelia/kernel';
import { MyApp } from './my-app';
const au = new Aurelia();
au.register(
StandardConfiguration,
AuthServiceRegistration,
AppTask.creating(() => {
// Initialize Auth0 before the app starts
const authService = resolve(IAuthService);
return authService.initialize();
})
);
au.app({ host: document.querySelector('my-app'), component: MyApp });
await au.start();
Authentication Component
// src/components/auth.ts
import { customElement } from '@aurelia/runtime-html';
import { resolve } from '@aurelia/kernel';
import { IAuthService } from '../services/auth';
import { User } from '@auth0/auth0-spa-js';
@customElement('auth-component')
export class AuthComponent {
isAuthenticated = false;
user: User | undefined;
isLoading = true;
private readonly authService: IAuthService = resolve(IAuthService);
async attached() {
try {
await this.authService.handleRedirectCallback();
this.isAuthenticated = await this.authService.isAuthenticated();
if (this.isAuthenticated) {
this.user = await this.authService.getUser();
}
} catch (error) {
console.error('Auth error:', error);
} finally {
this.isLoading = false;
}
}
async login() {
await this.authService.login();
}
logout() {
this.authService.logout();
}
}
<!-- src/components/auth.html -->
<div class="auth-component">
<div if.bind="isLoading">
Loading...
</div>
<div if.bind="!isLoading && !isAuthenticated">
<button click.trigger="login()">Login with Auth0</button>
</div>
<div if.bind="!isLoading && isAuthenticated">
<h3>Welcome, ${user.name}!</h3>
<p>Email: ${user.email}</p>
<button click.trigger="logout()">Logout</button>
</div>
</div>
Router Integration
Protect routes using Auth0:
// src/auth-guard.ts
import { lifecycleHooks } from '@aurelia/router';
import { resolve } from '@aurelia/kernel';
import { IAuthService } from './services/auth';
@lifecycleHooks()
export class AuthGuard {
private readonly authService: IAuthService = resolve(IAuthService);
async canLoad(): Promise<boolean> {
const isAuthenticated = await this.authService.isAuthenticated();
if (!isAuthenticated) {
await this.authService.login();
return false;
}
return true;
}
}
// src/my-app.ts
import { route } from '@aurelia/router';
import { AuthGuard } from './auth-guard';
@route({
routes: [
{ path: '', component: import('./home'), title: 'Home' },
{
path: '/protected',
component: import('./protected'),
title: 'Protected',
dependencies: [AuthGuard]
}
]
})
export class MyApp {}
API Calls with Tokens
Use access tokens for API requests:
// src/services/api.ts
import { resolve } from '@aurelia/kernel';
import { IAuthService } from './auth';
export class ApiService {
private readonly authService: IAuthService = resolve(IAuthService);
async makeAuthenticatedRequest(url: string, options: RequestInit = {}) {
try {
const token = await this.authService.getAccessToken();
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`
}
});
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
}
Best Practices
Store Auth0 credentials as environment variables
Use refresh tokens for better security in browsers that block third-party cookies
Handle token expiration gracefully
Implement proper error handling for authentication failures
Test authentication flows in different browsers
This integration follows Auth0's latest SDK patterns and Aurelia 2 best practices for dependency injection and component lifecycle management.
Last updated
Was this helpful?