Now.js Framework Documentation

Now.js Framework Documentation

AuthManager

EN 04 Sep 2026 01:40

AuthManager

Overview

AuthManager is the authentication management system in Now.js Framework. It supports JWT, session, and OAuth flows.

When to use:

  • Need login/logout
  • Need JWT authentication
  • Need role-based access control
  • Need auto token refresh

Why use it:

  • ✅ Multiple auth strategies (JWT, session)
  • ✅ Automatic token refresh
  • ✅ Rate limiting
  • ✅ Permission/role checking
  • ✅ HTTP interceptors
  • ✅ Security integration

Basic Usage

Initialization

await AuthManager.init({
  enabled: true,
  type: 'jwt-httponly',
  endpoints: {
    login: '/api/auth/login',
    logout: '/api/auth/logout',
    refresh: '/api/auth/refresh',
    user: '/api/auth/user'
  }
});

Login

try {
  await AuthManager.login({
    email: 'user@example.com',
    password: 'password123'
  });

  console.log('Logged in as:', AuthManager.getUser());
} catch (error) {
  console.error('Login failed:', error.message);
}

Logout

await AuthManager.logout();

Configuration

AuthManager.init({
  enabled: true,

  // Auth type: 'jwt', 'jwt-httponly', 'session'
  type: 'jwt-httponly',

  autoInit: true,

  endpoints: {
    login: '/api/auth/login',
    logout: '/api/auth/logout',
    refresh: '/api/auth/refresh',
    user: '/api/auth/user'
  },

  token: {
    // Storage: 'localStorage', 'sessionStorage', 'cookie'
    storage: 'cookie',
    key: 'auth_token',
    refreshKey: 'refresh_token',
    expiresKey: 'token_expires'
  },

  autoRefresh: {
    enabled: true,
    beforeExpiry: 60  // seconds before expiry
  },

  redirect: {
    afterLogin: '/',
    afterLogout: '/login',
    onUnauthorized: '/login'
  },

  rateLimit: {
    enabled: true,
    maxAttempts: 5,
    lockDuration: 300000  // 5 minutes
  }
});

API Reference

AuthManager.login(credentials, options)

Login user

Parameter Type Description
credentials object {email, password} or custom
options.redirect boolean Redirect after login

Returns: Promise<Object> - User data

const user = await AuthManager.login({
  email: 'user@example.com',
  password: 'password123'
});

AuthManager.logout(callServer?, options?)

Logout user

Parameter Type Description
callServer boolean Call logout endpoint (default: true)
options.redirect boolean Redirect after logout
await AuthManager.logout();

AuthManager.isAuthenticated()

Check authentication status

Returns: boolean

if (AuthManager.isAuthenticated()) {
  showProfileMenu();
}

AuthManager.getUser()

Get current user data

Returns: Object|null

const user = AuthManager.getUser();
console.log(user.name, user.email);

AuthManager.hasRole(role)

Check role

Parameter Type Description
role string Role name

Returns: boolean

if (AuthManager.hasRole('admin')) {
  showAdminPanel();
}

AuthManager.hasPermission(permission)

Check permission

Parameter Type Description
permission string Permission name

Returns: boolean

if (AuthManager.hasPermission('users.edit')) {
  showEditButton();
}

AuthManager.refreshToken()

Refresh access token

Returns: Promise<boolean>

AuthManager.checkAuthStatus()

Ask the verify endpoint who the current user is, update the session state, and
cache the user profile in local storage for display.

Returns: Promise<Object> — {authenticated, user}, plus offline: true
when the answer came from cache, or error when it failed.

Offline behaviour: a rejection by the server (401/403) clears the session as
before. A server that could not be reached does not: the cached profile is
restored and the result carries offline: true, so a dropped connection no
longer throws the user back to the login page — which would make an
offline-capable app unusable.

const status = await AuthManager.checkAuthStatus();
if (status.authenticated && status.offline) {
  // Working from the cached profile; show a "no connection" badge
}

Trade-off: if the session is revoked server-side while the device is
offline, the UI keeps showing the user as signed in until it is back online.
Nothing can be read or written in that state, because every API call is still
authorised by the server as usual — only the screen is stale. The next
successful verify clears the session.

AuthManager.isUnreachable(response)

Tell "the server could not be reached" apart from "the server said no".

simpleFetch returns status 0 when the fetch itself fails (offline, DNS
failure and the like) and 408 on timeout; a genuine rejection always carries
its own HTTP status. navigator.onLine === false also counts as unreachable.

Parameter Type Description
response Object Result of simpleFetch

Returns: boolean

AuthManager.restoreCachedUser()

Return the cached user profile and mark the session authenticated again.

Used only when the server could not be reached — never to skip a real
verification. Returns null when there is no usable cached profile, in which
case the caller must fall back to clearing the session.

Returns: Object|null

AuthManager.requireAuth()

Redirect if not authenticated

// Route guard
AuthManager.requireAuth();

AuthManager.requireGuest()

Redirect if authenticated

// Login page guard
AuthManager.requireGuest();

Events

Event When Triggered Detail
auth:initialized init() completed {authenticated, user}
auth:login Login succeeded {user, timestamp}
auth:logout Logout succeeded {timestamp}
auth:restored Impersonation ended, original admin restored {user, timestamp}
auth:token_refreshed Session refreshed successfully {user, token, timestamp}
auth:social_login_start Social login started {provider}
auth:error An auth error occurred {message, error, timestamp}
EventManager.on('auth:login', (data) => {
  console.log('User logged in:', data.user);
});

EventManager.on('auth:logout', () => {
  // Clear app state
  StateManager.reset();
});

Real-World Examples

Login Form

<form id="login-form">
  <input type="email" name="email" required>
  <input type="password" name="password" required>
  <button type="submit">Login</button>
</form>

<script>
document.getElementById('login-form').onsubmit = async (e) => {
  e.preventDefault();
  const form = e.target;

  try {
    await AuthManager.login({
      email: form.email.value,
      password: form.password.value
    });

    // Redirect to intended or dashboard
    RedirectManager.afterLogin();
  } catch (error) {
    NotificationManager.error(error.message);
  }
};
</script>

Protected Route

// Router middleware
RouterManager.beforeEach((to, from, next) => {
  const isProtected = to.meta?.requiresAuth;

  if (isProtected && !AuthManager.isAuthenticated()) {
    AuthManager.saveIntendedUrl(to.path);
    AuthManager.requireAuth();
    return;
  }

  next();
});

Role-Based UI

<nav>
  <a href="/" data-show-if="authenticated">Dashboard</a>

  <template data-if="hasRole('admin')">
    <a href="/admin">Admin Panel</a>
  </template>

  <a href="/login" data-hide-if="authenticated">Login</a>
  <a href="#" onclick="AuthManager.logout()" data-show-if="authenticated">Logout</a>
</nav>

API Request with Auth

// AuthManager auto-attaches token to requests
const response = await ApiService.get('/api/protected-resource');

// Handle auth errors
EventManager.on('auth:error', () => {
  AuthManager.requireAuth();
});

Common Pitfalls

⚠️ 1. Init Before Use

// ❌ Calling before init
AuthManager.login({...});

// ✅ Init first
await AuthManager.init({ enabled: true });
await AuthManager.login({...});

⚠️ 2. Check Auth Status

// ❌ Assuming authenticated without check
showProtectedContent();

// ✅ Check first
if (AuthManager.isAuthenticated()) {
  showProtectedContent();
}