Next Identity JavaScript SDK

Edited

The Next Identity JavaScript SDK provides a simple, framework-agnostic way to integrate OpenID Connect (OIDC) authentication into web applications.

It supports login, signup, profile management, protected pages, and logout using industry-standard OAuth 2.0 with PKCE (Proof Key for Code Exchange) for enhanced security — without requiring server-side code.

Table of Contents

  • Installation

  • Initialization

  • Authentication Actions

  • Authentication State

  • Protecting Your Application

  • Framework-Specific Auth Guards

  • Authenticated Components

  • User Interface Components

  • Events

  • API Reference

  • Complete Examples

  • Troubleshooting

Installation

Add the Next Identity SDK script inside the <head> tag of your HTML file.

<!DOCTYPE html>
<html>
<head>
  <title>My Application</title>
  <script src="https://idp.dev.nextidentity.io/sdk/ni-auth-js-sdk-1.0.0.min.js"></script>
</head>
<body>
</body>
</html>

Important

The SDK must be loaded in the <head>, not inside the <body>.
Once loaded, the SDK exposes a global NextIdentity object.

Initialization

Initialize the SDK at the end of the <body>, after your application content.

<body>
  <!-- Your application content -->

  <!-- Initialize the SDK at the end of the body -->
  <script>
    NextIdentity.Init({
      client_id: "your-client-id",
      issuer: "https://your-tenant.id.nextreason.com",
      login_redirect_uri: "https://yoursite.com/dashboard",
      logout_redirect_uri: "https://yoursite.com"
    });
  </script>
</body>

Configuration Options

Option

Type

Required

Default

Description

client_id

string

Yes

Client ID provided by Next Identity

issuer

string

Yes

Your Next Identity tenant URL

login_redirect_uri

string

No

window.location.origin

Redirect after login/signup

logout_redirect_uri

string

No

window.location.origin

Redirect after logout

auto_login

boolean

No

false

Automatically trigger login

Example

NextIdentity.Init({
  client_id: "fcdbc9150ff2400d9b72ff8d2022f7ec",
  issuer: "https://example.id.nextreason.com",
  login_redirect_uri: "https://myapp.com/dashboard",
  logout_redirect_uri: "https://myapp.com",
  auto_login: false
});

Authentication Actions

1. Trigger Login

Initiates the OIDC authorization flow.

Option A: Programmatic Method

NextIdentity.logIn();

Option B: Data Attribute (Recommended)

Add the data-ni-action="login" attribute to any clickable element:

<button data-ni-action="login">Login</button>
<a href="#" data-ni-action="login">Sign In</a>

Option C: Magic Link

Use the special href value that the SDK automatically detects:

<a href="https://login.nextidentity.io">Sign In</a>

Login Events

window.addEventListener('ni-auth-success', (event) => {
  console.log('User:', event.detail.token.user_profile);
});

window.addEventListener('ni-auth-fail', (event) => {
  console.error(event.detail.error);
});

2. Trigger Signup

Initiates the OIDC registration flow, redirecting the user to the Next Identity signup page.

Option A: Programmatic Method

NextIdentity.signUp();

Option B: Data Attribute (Recommended)

Add the data-ni-action="signup" attribute to any clickable element:

<button data-ni-action="signup">Sign Up</button>
<a href="https://signup.nextidentity.io">Create Account</a>

Option C: Magic Link

Use the special href value that the SDK automatically detects:

<a href="https://signup.nextidentity.io">Create Account</a>

3. Trigger Profile Management

Redirects the user to the Next Identity account management page where they can update their personal details, change password, and manage their account settings.

Option A: Programmatic Method

NextIdentity.manageProfile();

Option B: Data Attribute

Add the data-ni-action="profile" attribute to any clickable element:

<button data-ni-action="profile">Manage Account</button>
<a href="#" data-ni-action="profile">My Profile</a>

Option C: Built-in User Menu

After successful authentication, the SDK automatically renders a user menu dropdown that includes a "Profile" option. See Built-in User Menu for details.

4. Trigger Logout

Ends the user's session by clearing stored tokens and redirecting to the Next Identity logout endpoint.

Option A: Programmatic Method

NextIdentity.logOut();

Option B: Data Attribute

Add the data-ni-action="logout" attribute to any clickable element:

<button data-ni-action="logout">Sign Out</button>
<a href="#" data-ni-action="logout">Logout</a>

Option C: Magic Link

Use the special href value that the SDK automatically detects:

<a href="https://logout.nextidentity.io">Sign Out</a>

Option D: Built-in User Menu

The SDK's automatically rendered user menu includes a "Logout" option.

Logout Behavior

  1. Clears all tokens from localStorage

  2. Clears OIDC state from sessionStorage

  3. Redirects to the Next Identity end session endpoint

  4. After IdP logout, redirects to your configured logout_redirect_uri

Logout Events

window.addEventListener('ni-logout-fail', (event) => {
  console.error('Logout failed:', event.detail.error);
});

Authentication State

Check Authentication Status

Returns a boolean indicating whether the user is currently authenticated with a valid, non-expired token.

const isAuthenticated = NextIdentity.isAuthenticated();

if (isLoggedIn) {
  console.log('User is authenticated');
} else {
  console.log('User is not authenticated');
}

Safe framework pattern

const isAuthenticated =
  window.NextIdentity?.isAuthenticated?.() ?? false;

Get Stored Token Data

Retrieves the complete token data object stored after successful authentication. Returns null if the user is not authenticated.

const tokenData = NextIdentity.getTokenData();

if (tokenData) {
  console.log('Access Token:', tokenData.access_token);
  console.log('ID Token:', tokenData.id_token);
  console.log('Refresh Token:', tokenData.refresh_token);
  console.log('Expires At:', tokenData.expires_at);
  console.log('User Profile:', tokenData.user_profile);
}

Token structure

Property

Type

Description

access_token

string

OAuth access token

id_token

string

OIDC ID token

refresh_token

string

Refresh token

expires_at

number

Expiration timestamp

user_profile

object

Decoded user claims

User Profile Structure

Property

Type

Description

id

string

Unique user identifier (subject claim)

name

string

User's display name

email

string

User's email address

username

string

Username (typically the email)

firstname

string

User's first name

lastname

string

User's last name

Example: Using Access Token for API Calls

async function fetchProtectedData() {
  const tokenData = NextIdentity.getTokenData();
  
  if (!tokenData) {
    throw new Error('User not authenticated');
  }
  
  const response = await fetch('https://api.example.com/data', {
    headers: {
      'Authorization': `Bearer ${tokenData.access_token}`
    }
  });
  
  return response.json();
}

Example: Displaying User Information

function displayUserInfo() {
  const tokenData = NextIdentity.getTokenData();
  
  if (tokenData) {
    const user = tokenData.user_profile;
    document.getElementById('welcome-message').textContent = `Welcome, ${user.firstName}!`;
    document.getElementById('user-email').textContent = user.email;
  }
}

Authentication Check with Redirect

Verifies the user's authentication status and automatically redirects unauthenticated users to the configured logout_redirect_uri. Use this method to protect pages that require authentication.

NextIdentity.checkUserAuth();

Events

// Authentication check successful
window.addEventListener('ni-check-auth-success', (event) => {
  console.log('User verified:', event.detail.user);
  console.log('Token data:', event.detail.tokenData);
});

// Authentication check failed
window.addEventListener('ni-check-auth-fail', (event) => {
  console.error('Auth check failed:', event.detail.error);
});

Protecting Your Application

Protect Entire Pages

You can restrict access to entire pages, ensuring only authenticated users can view them. Unauthenticated users are automatically redirected away.

Option A: Body Attribute

Add the data-ni-auth-page attribute to the page's <body> tag:

<!DOCTYPE html>
<html>
<head>
  <title>Dashboard - Protected Page</title>
  <script src="https://idp.dev.nextidentity.io/sdk/ni-auth-js-sdk-1.0.0.min.js"></script>
</head>
<body data-ni-auth-page>
  <h1>Dashboard</h1>
  <p>This content is only accessible to authenticated users.</p>

  <script>
    NextIdentity.Init({
      client_id: 'your-client-id',
      issuer: 'https://your-tenant.id.nextreason.com',
      logout_redirect_uri: 'https://yoursite.com'
    });
  </script>
</body>
</html>

When data-ni-auth-page is present, the SDK automatically checks authentication status on page load. If the user is not authenticated or their token has expired, they are redirected to window.location.origin.

Option B: Programmatic

Use checkUserAuth() at the top of your protected page's script:

NextIdentity.Init({
  client_id: 'your-client-id',
  issuer: 'https://your-tenant.id.nextreason.com',
  logout_redirect_uri: 'https://yoursite.com'
});

// Redirects unauthenticated users to logout_redirect_uri
NextIdentity.checkUserAuth();

Option C: Custom Logic

For more control over the redirect behavior, use isAuthenticated():

if (!NextIdentity.isAuthenticated()) {
  // Custom redirect logic with return URL
  window.location.href = '/?returnUrl=' + encodeURIComponent(window.location.pathname);
} else {
  // User is authenticated, initialize the page
  initializeDashboard();
}

Prevent Flash of Protected Content

To prevent unauthenticated users from briefly seeing protected content before being redirected:

<style>
  .protected-content {
    visibility: hidden;
  }
  .protected-content.authenticated {
    visibility: visible;
  }
</style>

<body data-ni-auth-page>
  <div class="protected-content">
    <h1>Secret Dashboard</h1>
    <!-- Protected content here -->
  </div>

  <script>
    NextIdentity.Init({
      client_id: 'your-client-id',
      issuer: 'https://your-tenant.id.nextreason.com'
    });

    window.addEventListener('ni-check-auth-success', () => {
      document.querySelector('.protected-content').classList.add('authenticated');
    });
  </script>
</body>

Page Protection Methods Comparison

Method

Use Case

Redirect Target

data-ni-auth-page

Simple protection, minimal code

window.location.origin

checkUserAuth()

Programmatic control

logout_redirect_uri from config

isAuthenticated()

Custom logic, conditional redirects

Your custom URL

Framework-Specific Auth Guards

For single-page applications (SPAs) using modern frameworks, create an Auth Guard using the appropriate pattern for your framework.

Base Authentication Check

All framework implementations should use this pattern to check authentication:

const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;

React Auth Guard

Create a reusable wrapper component:

// components/AuthGuard.jsx
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

export function AuthGuard({ children }) {
  const navigate = useNavigate();
  const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;

  useEffect(() => {
    if (!isAuthenticated) {
      navigate('/');
    }
  }, [isAuthenticated, navigate]);

  if (!isAuthenticated) {
    return null; // or a loading spinner
  }

  return children;
}

Usage:

// App.jsx
import { AuthGuard } from './components/AuthGuard';

function App() {
  return (
    <Routes>
      <Route path="/" element={<HomePage />} />
      <Route path="/dashboard" element={
        <AuthGuard>
          <DashboardPage />
        </AuthGuard>
      } />
    </Routes>
  );
}

Vue Auth Guard

Create a navigation guard:

// guards/authGuard.js
export function authGuard(to, from, next) {
  const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;
  
  if (!isAuthenticated) {
    next('/');
  } else {
    next();
  }
}

Usage:

// router/index.js
import { authGuard } from '@/guards/authGuard';

const routes = [
  { path: '/', component: HomePage },
  { 
    path: '/dashboard', 
    component: DashboardPage,
    beforeEnter: authGuard
  }
];

Angular Auth Guard

Create a CanActivate guard service:

// guards/auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

declare global {
  interface Window {
    NextIdentity?: {
      isAuthenticated?: () => boolean;
    };
  }
}

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(): boolean {
    const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;
    
    if (!isAuthenticated) {
      this.router.navigate(['/']);
      return false;
    }
    
    return true;
  }
}

Usage:

// app-routing.module.ts
const routes: Routes = [
  { path: '', component: HomeComponent },
  { 
    path: 'dashboard', 
    component: DashboardComponent,
    canActivate: [AuthGuard]
  }
];

Plain JavaScript / Multi-Page Application (MPA)

Create a reusable function for protected pages:

// auth-guard.js
function requireAuth(redirectUrl = '/') {
  const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;
  
  if (!isAuthenticated) {
    window.location.href = redirectUrl;
    return false;
  }
  
  return true;
}

Usage on protected pages:

<script src="/js/auth-guard.js"></script>
<script>
  // Redirect to home if not authenticated
  requireAuth('/');
</script>

Authenticated Components

Mark elements to only be visible when the user is authenticated:

Using Data Attribute

<div data-ni-auth-component="true">
  Authenticated content
</div>

Using CSS Class

<div class="ni-auth-component">
  <button data-ni-action="profile">My Account</button>
  <button data-ni-action="logout">Sign Out</button>
</div>

Behavior

  • Elements are hidden by default (visibility: hidden)

  • After successful authentication, elements become visible

  • If the user is not authenticated, elements are removed from the DOM after a short delay

User Interface Components

Login and Signup Buttons

Add login and signup buttons to your application header or navigation:

<header>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    
    <!-- Authentication buttons -->
    <button data-ni-action="login">Login</button>
    <button data-ni-action="signup">Sign Up</button>
  </nav>
</header>

Note: After successful authentication, the SDK automatically hides these buttons and displays a user menu in their place.

Styled Example

<style>
  .auth-buttons button {
    padding: 8px 16px;
    margin-left: 8px;
    border-radius: 4px;
    cursor: pointer;
  }
  .auth-buttons button[data-ni-action="login"] {
    background: transparent;
    border: 1px solid #333;
  }
  .auth-buttons button[data-ni-action="signup"] {
    background: #007bff;
    color: white;
    border: none;
  }
</style>

<div class="auth-buttons">
  <button data-ni-action="login">Login</button>
  <button data-ni-action="signup">Sign Up</button>
</div>

Built-in User Menu

After successful authentication, the SDK automatically creates a user menu dropdown that replaces the login button. The menu displays:

  • User's initials in a circular avatar

  • User's name and email

  • Profile link (redirects to account management)

  • Logout link

Automatic Rendering

The user menu is automatically rendered when:

  1. The SDK detects a login button (data-ni-action="login" or href="https://login.nextidentity.io")

  2. The user is authenticated

The menu is injected as a sibling to the login button, wrapped in a .ni-user-info-wrapper container.


Menu Structure

┌─────────────────────┐
│  [AB]  ←── Avatar   │
├─────────────────────┤
│  Alice Brown        │
│  alice@example.com  │
├─────────────────────┤
│  👤 Profile         │
│  🚪 Logout          │
└─────────────────────┘

Customizing User Menu Styles

The built-in user menu has inline styles, but you can override them:

/* Override wrapper styles */
.ni-user-info-wrapper {
  /* Your custom styles */
}

/* Override menu dropdown styles */
.ni-user-info-menu {
  /* Your custom styles */
}

Events

The SDK dispatches custom events that you can listen to for handling authentication state changes.

Event Reference

Event

Trigger

Description

ni-auth-success

Successful login/signup

token (full token data object)

ni-auth-fail

Login/signup failed

error (error message)

ni-login-fail

Login initiation failed

error (error message)

ni-logout-fail

Logout failed

error (error message)

ni-check-auth-success

Auth check passed

user, tokenData

ni-check-auth-fail

Auth check failed

error (error message)

Listening to Events

// Handle successful authentication
window.addEventListener('ni-auth-success', (event) => {
  const { token } = event.detail;
  console.log('User logged in:', token.user_profile.name);
  
  // Redirect to dashboard or update UI
  window.location.href = '/dashboard';
});

// Handle authentication failure
window.addEventListener('ni-auth-fail', (event) => {
  console.error('Authentication failed:', event.detail.error);
  showErrorMessage('Login failed. Please try again.');
});

// Handle auth check success (for protected pages)
window.addEventListener('ni-check-auth-success', (event) => {
  const { user, tokenData } = event.detail;
  console.log('Authenticated user:', user.email);
  initializeProtectedPage(tokenData);
});

API Reference

Methods

Method

Description

Parameters

Returns

Init()

Initialize SDK

config object

void

logIn()

Start login

void

signUp()

Start signup

void

manageProfile()

Open profile

void

logOut()

Logout

void

isAuthenticated()

Auth status

boolean

getTokenData()

Token data

object | null

checkUserAuth()

Verify auth

void

Data Attributes

Attribute

Value

Element

Description

data-ni-action

"login"

Any clickable

Triggers login flow on click

data-ni-action

"signup"

Any clickable

Triggers signup flow on click

data-ni-action

"logout"

Any clickable

Triggers logout flow on click

data-ni-action

"profile"

Any clickable

Triggers profile management on click

data-ni-auth-page

<body>

Protects entire page, redirects if unauthenticated

data-ni-auth-component

"true"

Any element

Shows element only when authenticated

CSS Classes

Class

Description

.ni-auth-component

Shows element only when authenticated

.ni-user-info-wrapper

Container for the built-in user menu

.ni-user-info-menu

The dropdown menu element

Magic Links

URL

Action

https://login.nextidentity.io

Triggers login flow

https://signup.nextidentity.io

Triggers signup flow

https://logout.nextidentity.io

Triggers logout flow

Complete Examples

Basic HTML Integration

<!DOCTYPE html>
<html>
<head>
  <title>My App</title>
  <script src="https://idp.dev.nextidentity.io/sdk/ni-auth-js-sdk-1.0.0.min.js"></script>
  <style>
    nav { display: flex; gap: 16px; align-items: center; padding: 16px; }
    nav a { text-decoration: none; color: #333; }
    .spacer { flex: 1; }
    button { padding: 8px 16px; cursor: pointer; }
  </style>
</head>
<body>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    <span class="spacer"></span>
    <button data-ni-action="login">Login</button>
    <button data-ni-action="signup">Sign Up</button>
  </nav>

  <main>
    <h1>Welcome to My App</h1>
    
    <!-- Only visible when authenticated -->
    <div data-ni-auth-component="true">
      <p>You are logged in!</p>
      <button data-ni-action="profile">Manage Account</button>
    </div>
  </main>

  <script>
    NextIdentity.Init({
      client_id: "your-client-id",
      issuer: "https://your-tenant.id.nextreason.com",
      login_redirect_uri: window.location.origin,
      logout_redirect_uri: window.location.origin
    });

    // Handle successful authentication
    window.addEventListener('ni-auth-success', (event) => {
      const user = event.detail.token.user_profile;
      console.log(`Welcome, ${user.name}!`);
    });
  </script>
</body>
</html>

Protected Dashboard Page

<!DOCTYPE html>
<html>
<head>
  <title>Dashboard - My App</title>
  <script src="https://idp.dev.nextidentity.io/sdk/ni-auth-js-sdk-1.0.0.min.js"></script>
  <style>
    .dashboard { padding: 20px; visibility: hidden; }
    .dashboard.ready { visibility: visible; }
  </style>
</head>
<body data-ni-auth-page>
  <nav>
    <a href="/">Home</a>
    <button data-ni-action="logout">Sign Out</button>
  </nav>

  <main class="dashboard">
    <h1>Dashboard</h1>
    <div id="user-info"></div>
  </main>

  <script>
    NextIdentity.Init({
      client_id: "your-client-id",
      issuer: "https://your-tenant.id.nextreason.com",
      logout_redirect_uri: window.location.origin
    });

    window.addEventListener('ni-check-auth-success', (event) => {
      const user = event.detail.user;
      
      // Display user info
      document.getElementById('user-info').innerHTML = `
        <p>Welcome back, <strong>${user.name}</strong>!</p>
        <p>Email: ${user.email}</p>
      `;
      
      // Show the dashboard
      document.querySelector('.dashboard').classList.add('ready');
    });
  </script>
</body>
</html>

React SPA Integration

// index.html - Add SDK to head
<head>
  <script src="https://idp.dev.nextidentity.io/sdk/ni-auth-js-sdk-1.0.0.min.js"></script>
</head>

// App.jsx
import { useEffect } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AuthGuard } from './components/AuthGuard';
import HomePage from './pages/HomePage';
import DashboardPage from './pages/DashboardPage';

function App() {
  useEffect(() => {
    window.NextIdentity?.Init({
      client_id: "your-client-id",
      issuer: "https://your-tenant.id.nextreason.com",
      login_redirect_uri: window.location.origin + '/dashboard',
      logout_redirect_uri: window.location.origin
    });
  }, []);

  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/dashboard" element={
          <AuthGuard>
            <DashboardPage />
          </AuthGuard>
        } />
      </Routes>
    </BrowserRouter>
  );
}

// components/AuthGuard.jsx
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

export function AuthGuard({ children }) {
  const navigate = useNavigate();
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const isAuthenticated = window.NextIdentity?.isAuthenticated?.() ?? false;
    
    if (!isAuthenticated) {
      navigate('/');
    } else {
      setIsReady(true);
    }
  }, [navigate]);

  if (!isReady) return <div>Loading...</div>;
  
  return children;
}

// components/Header.jsx
export function Header() {
  return (
    <header>
      <nav>
        <a href="/">Home</a>
        <button data-ni-action="login">Login</button>
        <button data-ni-action="signup">Sign Up</button>
      </nav>
    </header>
  );
}

Troubleshooting

SDK not loading

  • Script must be in <head>

  • Check network errors

Login not working

  • Validate client_id and issuer

  • Confirm redirect URIs

User menu missing

  • Ensure a login button exists

  • Check isAuthenticated()

Debugging

// Check if authenticated
console.log('Authenticated:', NextIdentity.isAuthenticated());

// View token data
console.log('Token data:', NextIdentity.getTokenData());

// View stored tokens (raw)
console.log('Raw tokens:', localStorage.getItem('oidc_tokens'));

Was this article helpful?

Sorry about that! Care to tell us more?

Thanks for the feedback!

There was an issue submitting your feedback
Please check your connection and try again.