Auth0.js
Authentication Library
Auth0.js
Overview
Auth0.js is Auth0's official JavaScript SDK for Web (browser) applications, remaining a primary choice for Single Page Application (SPA) authentication as of 2025. The latest v10 series provides comprehensive support for OAuth 2.0, OpenID Connect, and PKCE (Proof Key for Code Exchange), offering rich authentication flows (Universal Login, Silent Authentication, Refresh Token Rotation) and diverse authentication provider integrations (Google, Facebook, Microsoft, GitHub, etc.). With seamless integration with modern JavaScript frameworks like React, Vue.js, and Angular, automated token management, and built-in security best practices, Auth0.js enables efficient implementation of enterprise-level web application authentication.
Details
Auth0.js v10 delivers advanced authentication capabilities leveraging modern browser APIs. The architecture consists of three main components: authentication client, token management, and user profile management, enabling secure SPA authentication. It features Universal Login for single sign-on (SSO), Silent Authentication for transparent token refresh, Refresh Token Rotation for enhanced security, and PKCE implementation to prevent authorization code attacks as standard equipment. Integration with multi-factor authentication (MFA), conditional access, custom claims, and Role-Based Access Control (RBAC) allows building flexible and secure authentication systems.
Key Features
- Universal Login: Unified authentication experience through Auth0-hosted login pages
- PKCE Support: Secure authentication flow optimized for Single Page Applications
- Silent Authentication: Enhanced user experience through transparent token refresh
- Multiple Auth Providers: Integration with Google, Facebook, Microsoft, GitHub, etc.
- Token Management: Automated management of JWT, Access Token, and Refresh Token
- Framework Integration: Official integration with React, Vue.js, Angular, etc.
Advantages and Disadvantages
Advantages
- High reliability and long-term support guaranteed as Auth0's official SDK
- Unified user experience through Universal Login
- Automatic application of SPA security best practices through PKCE implementation
- Enhanced development efficiency with pre-integrated authentication providers
- Simplified operational management through complete Auth0 dashboard integration
- Development support through detailed documentation and community support
Disadvantages
- Migration to other authentication providers is difficult due to Auth0 service dependency
- Commercial usage costs increase with the number of users
- Advanced customization requires deep understanding of Auth0 platform
- Cannot be used in offline environments due to network connection dependency
- Limited control level compared to self-hosted authentication systems
- During debugging, distinguishing between Auth0 service-side issues can be challenging
Reference Pages
Usage Examples
Installation and Setup
# Installation using npm
npm install auth0-js
# Or, load directly from CDN
# <script src="https://cdn.auth0.com/js/auth0/9.20.2/auth0.min.js"></script>
// auth-config.js - Auth0 Configuration
import auth0 from 'auth0-js';
// Auth0 configuration object
const authConfig = {
domain: 'your-tenant.auth0.com',
clientID: 'your-client-id',
redirectUri: window.location.origin + '/callback',
responseType: 'code',
scope: 'openid profile email',
audience: 'https://your-api-identifier'
};
// Auth0 client instance
const auth0Client = new auth0.WebAuth(authConfig);
export { auth0Client, authConfig };
Basic Authentication Flow Implementation
// auth-service.js - Authentication Service
import { auth0Client } from './auth-config.js';
class AuthService {
constructor() {
this.tokenRenewalTimeout = null;
this.isAuthenticated = false;
this.userProfile = null;
this.accessToken = null;
this.idToken = null;
// Check for existing tokens on initialization
this.checkSession();
}
// Start login
login() {
console.log('Starting Auth0 login...');
auth0Client.authorize();
}
// Handle callback
handleAuthentication() {
return new Promise((resolve, reject) => {
auth0Client.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
console.log('Authentication successful:', authResult);
this.setSession(authResult);
resolve(authResult);
} else if (err) {
console.error('Authentication error:', err);
reject(err);
}
});
});
}
// Set session
setSession(authResult) {
// Store tokens
this.accessToken = authResult.accessToken;
this.idToken = authResult.idToken;
this.isAuthenticated = true;
// Save to localStorage
localStorage.setItem('access_token', authResult.accessToken);
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('expires_at',
JSON.stringify(authResult.expiresIn * 1000 + new Date().getTime())
);
// Get user profile
this.getUserProfile((err, profile) => {
if (profile) {
this.userProfile = profile;
localStorage.setItem('user_profile', JSON.stringify(profile));
}
});
// Schedule token renewal
this.scheduleRenewal();
// Notify authentication state change
this.notifyAuthenticationChange();
}
// Get user profile
getUserProfile(callback) {
if (!this.accessToken) {
callback(new Error('Access token not available'), null);
return;
}
auth0Client.client.userInfo(this.accessToken, (err, profile) => {
if (profile) {
console.log('User profile retrieved successfully:', profile);
}
callback(err, profile);
});
}
// Logout
logout() {
// Clear local state
this.accessToken = null;
this.idToken = null;
this.userProfile = null;
this.isAuthenticated = false;
// Clear localStorage
localStorage.removeItem('access_token');
localStorage.removeItem('id_token');
localStorage.removeItem('expires_at');
localStorage.removeItem('user_profile');
// Clear token renewal timer
clearTimeout(this.tokenRenewalTimeout);
// Logout from Auth0
auth0Client.logout({
returnTo: window.location.origin,
clientID: auth0Client.clientID
});
console.log('Logout completed');
}
// Check session (silent authentication)
checkSession() {
auth0Client.checkSession({}, (err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
console.log('Existing session detected');
this.setSession(authResult);
} else if (err && err.error !== 'login_required') {
console.log('Session check error:', err);
this.logout();
}
});
}
// Check token validity
isTokenValid() {
const expiresAt = JSON.parse(localStorage.getItem('expires_at') || '0');
return new Date().getTime() < expiresAt;
}
// Schedule token renewal
scheduleRenewal() {
const expiresAt = JSON.parse(localStorage.getItem('expires_at') || '0');
const timeout = expiresAt - Date.now();
if (timeout > 0) {
this.tokenRenewalTimeout = setTimeout(() => {
this.renewToken();
}, timeout - 30000); // Renew 30 seconds before expiry
}
}
// Renew token
renewToken() {
auth0Client.checkSession({}, (err, result) => {
if (err) {
console.log('Token renewal error:', err);
this.logout();
} else {
console.log('Token renewal successful');
this.setSession(result);
}
});
}
// Helper for authenticated API calls
async authenticatedFetch(url, options = {}) {
if (!this.isTokenValid()) {
throw new Error('Authentication token is invalid');
}
const authOptions = {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
}
};
try {
const response = await fetch(url, authOptions);
if (response.status === 401) {
console.log('API returned 401 - attempting token renewal');
await this.renewToken();
// Retry with renewed token
authOptions.headers['Authorization'] = `Bearer ${this.accessToken}`;
return fetch(url, authOptions);
}
return response;
} catch (error) {
console.error('API call error:', error);
throw error;
}
}
// Notify authentication state change
notifyAuthenticationChange() {
const event = new CustomEvent('authStateChanged', {
detail: {
isAuthenticated: this.isAuthenticated,
userProfile: this.userProfile
}
});
window.dispatchEvent(event);
}
}
// Singleton instance
const authService = new AuthService();
export default authService;
React Integration Implementation
// AuthContext.jsx - React Authentication Context
import React, { createContext, useContext, useEffect, useState } from 'react';
import authService from './auth-service.js';
const AuthContext = createContext();
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
export const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [userProfile, setUserProfile] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// Initialize authentication
const initializeAuth = async () => {
try {
setLoading(true);
// Handle callback from URL
if (window.location.hash.includes('access_token') ||
window.location.hash.includes('error')) {
await authService.handleAuthentication();
window.location.hash = '';
}
// Set current authentication state
setIsAuthenticated(authService.isAuthenticated);
setUserProfile(authService.userProfile);
} catch (err) {
console.error('Authentication initialization error:', err);
setError(err.message);
} finally {
setLoading(false);
}
};
initializeAuth();
// Listen for authentication state changes
const handleAuthChange = (event) => {
setIsAuthenticated(event.detail.isAuthenticated);
setUserProfile(event.detail.userProfile);
};
window.addEventListener('authStateChanged', handleAuthChange);
return () => {
window.removeEventListener('authStateChanged', handleAuthChange);
};
}, []);
const login = () => {
setError(null);
authService.login();
};
const logout = () => {
authService.logout();
setIsAuthenticated(false);
setUserProfile(null);
};
const value = {
isAuthenticated,
userProfile,
loading,
error,
login,
logout,
authenticatedFetch: authService.authenticatedFetch.bind(authService)
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
};
// LoginButton.jsx - Login Button Component
import React from 'react';
import { useAuth } from './AuthContext.jsx';
const LoginButton = () => {
const { isAuthenticated, login, logout, userProfile, loading } = useAuth();
if (loading) {
return <div>Loading...</div>;
}
if (isAuthenticated) {
return (
<div className="user-info">
<img
src={userProfile?.picture}
alt="Profile"
className="profile-picture"
/>
<span>Hello, {userProfile?.name}!</span>
<button onClick={logout} className="logout-button">
Logout
</button>
</div>
);
}
return (
<button onClick={login} className="login-button">
Login
</button>
);
};
export default LoginButton;
// ProtectedRoute.jsx - Protected Route Component
import React from 'react';
import { useAuth } from './AuthContext.jsx';
const ProtectedRoute = ({ children, fallback = null }) => {
const { isAuthenticated, loading } = useAuth();
if (loading) {
return <div>Checking authentication...</div>;
}
if (!isAuthenticated) {
return fallback || (
<div className="unauthorized">
<h2>Authentication Required</h2>
<p>Please log in to access this page.</p>
</div>
);
}
return children;
};
export default ProtectedRoute;
Vue.js Integration Implementation
// auth-plugin.js - Vue.js Authentication Plugin
import authService from './auth-service.js';
const AuthPlugin = {
install(app) {
// Reactive authentication state
const authState = app.config.globalProperties.$authState = reactive({
isAuthenticated: authService.isAuthenticated,
userProfile: authService.userProfile,
loading: true
});
// Provide authentication methods globally
app.config.globalProperties.$auth = {
login: authService.login.bind(authService),
logout: authService.logout.bind(authService),
authenticatedFetch: authService.authenticatedFetch.bind(authService)
};
// Listen for authentication state changes
window.addEventListener('authStateChanged', (event) => {
authState.isAuthenticated = event.detail.isAuthenticated;
authState.userProfile = event.detail.userProfile;
});
// Initialize
app.mixin({
async created() {
if (this.$root === this) {
// Initialize only in root component
try {
// Handle callback
if (window.location.hash.includes('access_token')) {
await authService.handleAuthentication();
window.location.hash = '';
}
authState.isAuthenticated = authService.isAuthenticated;
authState.userProfile = authService.userProfile;
} catch (error) {
console.error('Authentication initialization error:', error);
} finally {
authState.loading = false;
}
}
}
});
}
};
export default AuthPlugin;
// main.js - Vue.js Application Setup
import { createApp, reactive } from 'vue';
import App from './App.vue';
import AuthPlugin from './auth-plugin.js';
const app = createApp(App);
app.use(AuthPlugin);
app.mount('#app');
Angular Integration Implementation
// auth.service.ts - Angular Authentication Service
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { auth0Client } from './auth-config';
interface AuthState {
isAuthenticated: boolean;
userProfile: any;
loading: boolean;
error: string | null;
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
private authStateSubject = new BehaviorSubject<AuthState>({
isAuthenticated: false,
userProfile: null,
loading: true,
error: null
});
public authState$: Observable<AuthState> = this.authStateSubject.asObservable();
constructor() {
this.initializeAuth();
}
private async initializeAuth(): Promise<void> {
try {
// Handle callback
if (window.location.hash.includes('access_token')) {
await this.handleAuthentication();
window.location.hash = '';
}
// Check existing session
this.checkSession();
} catch (error) {
this.updateAuthState({ error: error.message });
} finally {
this.updateAuthState({ loading: false });
}
}
login(): void {
this.updateAuthState({ error: null });
auth0Client.authorize();
}
logout(): void {
auth0Client.logout({
returnTo: window.location.origin,
clientID: auth0Client.clientID
});
this.updateAuthState({
isAuthenticated: false,
userProfile: null
});
}
private handleAuthentication(): Promise<any> {
return new Promise((resolve, reject) => {
auth0Client.parseHash((err, authResult) => {
if (authResult && authResult.accessToken) {
this.setSession(authResult);
resolve(authResult);
} else if (err) {
reject(err);
}
});
});
}
private setSession(authResult: any): void {
localStorage.setItem('access_token', authResult.accessToken);
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('expires_at',
JSON.stringify(authResult.expiresIn * 1000 + new Date().getTime())
);
this.getUserProfile();
this.updateAuthState({ isAuthenticated: true });
}
private getUserProfile(): void {
const accessToken = localStorage.getItem('access_token');
if (!accessToken) return;
auth0Client.client.userInfo(accessToken, (err, profile) => {
if (profile) {
this.updateAuthState({ userProfile: profile });
}
});
}
private checkSession(): void {
auth0Client.checkSession({}, (err, authResult) => {
if (authResult && authResult.accessToken) {
this.setSession(authResult);
}
});
}
private updateAuthState(updates: Partial<AuthState>): void {
const currentState = this.authStateSubject.value;
this.authStateSubject.next({ ...currentState, ...updates });
}
}
// auth.guard.ts - Angular Authentication Guard
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable, map, take } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(): Observable<boolean> {
return this.authService.authState$.pipe(
take(1),
map(state => {
if (state.isAuthenticated) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
})
);
}
}