Auth0.js

authentication libraryAuth0JavaScriptSPAOAuth 2.0OpenID ConnectJWTbrowser authentication

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;
        }
      })
    );
  }
}