npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

diksuchi-onelink

v1.2.0

Published

Official authentication SDK for Diksuchi platforms - OAuth2 with PKCE, React hooks, and enterprise security

Readme

diksuchi-onelink

Official authentication SDK for Diksuchi platforms - OAuth2 with PKCE, React hooks, and enterprise security

npm version npm downloads Bundle Size TypeScript License: MIT Build Status codecov PRs Welcome

🚀 Features

  • OAuth 2.0 with PKCE - Secure authorization code flow
  • React Hooks & Components - Pre-built UI components and hooks
  • TypeScript First - Full type safety and IntelliSense
  • Auto Token Refresh - Automatic token renewal before expiry
  • Server Middleware - Next.js, Express, and generic middleware
  • Role-Based Access Control - App-specific permissions
  • Zero Dependencies - Only jose for JWT verification
  • Tree-Shakeable - Import only what you need
  • SSR Ready - Works with Next.js and server-side rendering

📦 Installation

npm install diksuchi-onelink
# or
yarn add diksuchi-onelink
# or
pnpm add diksuchi-onelink

� Browser Compatibility

diksuchi-onelink works in all modern browsers that support:

  • ES2020 features
  • Web Crypto API (crypto.subtle)
  • fetch API
  • Promise and async/await

Supported Browsers

| Browser | Minimum Version | |---------|----------------| | Chrome | 80+ | | Firefox | 75+ | | Safari | 13.1+ | | Edge | 80+ | | Opera | 67+ |

Node.js Support

  • Node.js 18.x or higher (for server-side usage)
  • Requires Web Crypto API (available in Node 15+)

Required Browser APIs

The package uses these Web APIs:

  • Web Crypto API - For PKCE generation and SHA-256 hashing
  • Fetch API - For OAuth token requests
  • Storage API - For token persistence (localStorage/sessionStorage)
  • URL API - For OAuth redirect handling

Polyfills

For older browsers, you may need polyfills for:

�🎯 Quick Start

React Application (5 minutes setup)

import { DiksuchiAuthProvider, useAuth, LoginButton } from 'diksuchi-onelink/react';

// 1. Wrap your app with DiksuchiAuthProvider
function App() {
  return (
    <DiksuchiAuthProvider
      config={{
        clientId: 'your-app-id', // e.g., 'projectshub'
        authServerUrl: 'https://diksuchi-auth-identity.vercel.app',
      }}
      autoHandleCallback={true}
    >
      <YourApp />
    </DiksuchiAuthProvider>
  );
}

// 2. Use authentication in your components
function YourApp() {
  const { user, isAuthenticated, login, logout } = useAuth();

  if (!isAuthenticated) {
    return <LoginButton />;
  }

  return (
    <div>
      <h1>Welcome, {user?.name || user?.email}!</h1>
      <button onClick={() => logout()}>Logout</button>
    </div>
  );
}

Vanilla JavaScript

import { DiksuchiAuth } from 'diksuchi-onelink';

const auth = new DiksuchiAuth({
  clientId: 'your-app-id',
});

// Login
await auth.login();

// On callback page
const user = await auth.handleCallback();
console.log('Logged in as:', user.email);

// Get access token
const token = auth.getAccessToken();

// Check roles
if (auth.hasRole('projectshub', 'creator')) {
  console.log('User is a creator!');
}

// Logout
await auth.logout();

Server-Side (Next.js API Routes)

import { createNextAuthMiddleware } from 'diksuchi-onelink/server';
import { NextRequest, NextResponse } from 'next/server';

const withAuth = createNextAuthMiddleware({
  requiredRoles: {
    app: 'projectshub',
    roles: ['creator'],
  },
});

export const GET = withAuth(async (request: NextRequest, user) => {
  // user is automatically verified and typed
  return NextResponse.json({
    message: `Hello ${user.email}!`,
    roles: user.apps.projectshub,
  });
});

📚 Documentation

Table of Contents


⚙️ Configuration

DiksuchiAuthConfig

interface DiksuchiAuthConfig {
  /** OAuth client ID for your application (required) */
  clientId: string;
  
  /** Auth server URL (default: https://diksuchi-auth-identity.vercel.app) */
  authServerUrl?: string;
  
  /** Redirect URI (auto-detected if not provided) */
  redirectUri?: string;
  
  /** OAuth scopes (default: ['openid', 'profile', 'email']) */
  scopes?: string[];
  
  /** Storage type (default: sessionStorage) */
  storage?: 'localStorage' | 'sessionStorage' | 'memory';
  
  /** Auto-refresh tokens (default: true) */
  autoRefresh?: boolean;
  
  /** Refresh threshold in seconds (default: 60) */
  refreshThreshold?: number;
  
  /** Enable debug logging (default: false) */
  debug?: boolean;
  
  /** Callbacks */
  onAuthStateChange?: (user: DiksuchiUser | null) => void;
  onTokenRefresh?: (tokens: TokenResponse) => void;
  onError?: (error: AuthError) => void;
}

Pre-defined Client IDs

import { DiksuchiApp } from 'diksuchi-onelink';

DiksuchiApp.Main           // 'diksuchi'
DiksuchiApp.ProjectsHub    // 'projectshub'
DiksuchiApp.ChallengeHub   // 'challengehub'
DiksuchiApp.PDFHub         // 'pdfhub'
DiksuchiApp.AICodeEditor   // 'aicodeeditor'

🎣 React Hooks

useAuth()

Main hook for authentication state and actions.

import { useAuth } from 'diksuchi-onelink/react';

function MyComponent() {
  const {
    user,              // Current user or null
    isAuthenticated,   // Boolean
    isLoading,         // Boolean
    accessToken,       // JWT access token
    error,             // AuthError or null
    login,             // Function to initiate login
    logout,            // Function to logout
    refreshToken,      // Function to manually refresh token
    hasRole,           // Check single role
    checkRoles,        // Check multiple roles
  } = useAuth();
}

useUser()

Get current user.

const user = useUser(); // DiksuchiUser | null

useIsAuthenticated()

Check authentication status.

const isAuthenticated = useIsAuthenticated(); // boolean

useHasRole()

Check if user has a specific role.

const isCreator = useHasRole('projectshub', 'creator'); // boolean

useAccessToken()

Get access token for API calls.

const token = useAccessToken();

// Use in fetch
fetch('/api/data', {
  headers: {
    'Authorization': `Bearer ${token}`,
  },
});

🧩 Components

LoginButton

Pre-built login button with loading state.

<LoginButton
  options={{ loginHint: '[email protected]' }}
  onLoginStart={() => console.log('Login started')}
  className="btn-primary"
>
  Sign in with Diksuchi
</LoginButton>

LogoutButton

Pre-built logout button.

<LogoutButton
  options={{ revokeAllSessions: true }}
  onLogoutComplete={() => console.log('Logged out')}
>
  Sign out
</LogoutButton>

AuthGuard

Protect routes/components behind authentication.

<AuthGuard
  fallback={<LoginPage />}
  loginRedirect={true}
  requiredRoles={{
    app: 'projectshub',
    roles: ['creator'],
  }}
  forbiddenFallback={<AccessDenied />}
>
  <ProtectedContent />
</AuthGuard>

RoleGuard

Conditionally render based on roles.

<RoleGuard
  app="projectshub"
  roles={['admin', 'moderator']}
  requireAll={false} // User needs at least one role
  fallback={<div>Access denied</div>}
>
  <AdminPanel />
</RoleGuard>

UserProfile

Display user information.

<UserProfile
  showEmail={true}
  showPicture={true}
  className="user-profile"
/>

CallbackHandler

Handle OAuth callback on callback page.

// pages/auth/callback.tsx
import { CallbackHandler } from 'diksuchi-onelink/react';
import { useRouter } from 'next/router';

export default function Callback() {
  const router = useRouter();

  return (
    <CallbackHandler
      onSuccess={(user) => {
        console.log('Logged in:', user);
        router.push('/dashboard');
      }}
      onError={(error) => {
        console.error('Login failed:', error);
        router.push('/login');
      }}
      loadingComponent={<div>Logging you in...</div>}
    />
  );
}

💻 Client API

DiksuchiAuth Class

import { DiksuchiAuth } from 'diksuchi-onelink';

const auth = new DiksuchiAuth({
  clientId: 'projectshub',
  debug: true,
});

Methods

login(options?)

Initiate OAuth login flow.

await auth.login({
  loginHint: '[email protected]',
  prompt: 'login', // Force fresh login
  additionalScopes: ['admin'],
});

handleCallback(callbackUrl?)

Handle OAuth callback and exchange code for tokens.

const user = await auth.handleCallback();

logout(options?)

Logout user and clear tokens.

await auth.logout({
  revokeAllSessions: true,
  returnTo: '/goodbye',
});

refreshToken(options?)

Manually refresh access token.

const tokens = await auth.refreshToken({ force: true });

getUser()

Get current user.

const user = auth.getUser();

getAccessToken()

Get access token for API calls.

const token = auth.getAccessToken();

isAuthenticated()

Check if user is authenticated.

if (auth.isAuthenticated()) {
  // User is logged in
}

hasRole(app, role)

Check if user has specific role.

if (auth.hasRole('projectshub', 'creator')) {
  // User is a creator
}

checkRoles(app, roles)

Check multiple roles.

const check = auth.checkRoles('projectshub', ['admin', 'moderator']);
if (check.hasRole) {
  console.log('User has all required roles');
} else {
  console.log('Missing roles:', check.missingRoles);
}

subscribe(listener)

Subscribe to auth state changes.

const unsubscribe = auth.subscribe((state) => {
  console.log('Auth state changed:', state);
});

// Cleanup
unsubscribe();

🔐 Server Middleware

Next.js App Router

// app/api/protected/route.ts
import { createNextAuthMiddleware } from 'diksuchi-onelink/server';
import { NextRequest, NextResponse } from 'next/server';

const withAuth = createNextAuthMiddleware({
  requiredRoles: {
    app: 'projectshub',
    roles: ['creator'],
  },
  requireEmailVerified: true,
});

export const GET = withAuth(async (request: NextRequest, user) => {
  return NextResponse.json({ user });
});

Express

import express from 'express';
import { createExpressAuthMiddleware } from 'diksuchi-onelink/server';

const app = express();

const requireAuth = createExpressAuthMiddleware({
  requiredRoles: {
    app: 'projectshub',
    roles: ['creator'],
  },
});

app.get('/api/protected', requireAuth, (req, res) => {
  res.json({ user: req.user });
});

Generic Framework

import { createAuthMiddleware } from 'diksuchi-onelink/server';

const auth = createAuthMiddleware({
  requiredRoles: {
    app: 'projectshub',
    roles: ['creator'],
  },
});

// In your handler
const authHeader = request.headers.get('authorization');
const user = await auth.authenticate(authHeader);

Token Verification

import { verifyToken } from 'diksuchi-onelink/server';

const user = await verifyToken(accessToken);
if (user) {
  console.log('Valid user:', user.email);
}

🛡️ Role-Based Access Control

User Object

interface DiksuchiUser {
  sub: string;          // User ID
  email: string;        // User email
  name?: string;        // User name
  emailVerified?: boolean;
  picture?: string;     // Profile picture URL
  apps: {               // App-specific roles
    [appId: string]: string[];
  };
}

Example User

{
  sub: "user_123",
  email: "[email protected]",
  name: "John Doe",
  apps: {
    diksuchi: ["student", "instructor"],
    projectshub: ["creator", "admin"],
    pdfhub: ["user"]
  }
}

Check Roles

import { hasRole, hasAnyRole, hasAllRoles } from 'diksuchi-onelink/server';

// Single role
if (hasRole(user, 'projectshub', 'creator')) {
  // User is a creator
}

// Any role
if (hasAnyRole(user, 'projectshub', ['admin', 'moderator'])) {
  // User is admin OR moderator
}

// All roles
if (hasAllRoles(user, 'diksuchi', ['student', 'instructor'])) {
  // User is both student AND instructor
}

🔧 Advanced Usage

Custom Storage

import { DiksuchiAuth } from 'diksuchi-onelink';

const auth = new DiksuchiAuth({
  clientId: 'projectshub',
  storage: 'localStorage', // Persists across browser sessions
});

Manual Token Management

import { TokenManager } from 'diksuchi-onelink';

const tokenManager = new TokenManager('localStorage');

// Save tokens
tokenManager.saveTokens(tokens);

// Check expiration
if (tokenManager.isTokenExpired(60)) {
  // Token expires in less than 60 seconds
}

// Get time until expiry
const seconds = tokenManager.getTimeUntilExpiry();

PKCE Utilities

import { generatePKCEChallenge, generateState } from 'diksuchi-onelink';

// Generate PKCE challenge
const pkce = await generatePKCEChallenge();
console.log(pkce.verifier);  // Store this
console.log(pkce.challenge); // Send to server

// Generate state for CSRF protection
const state = generateState();

Error Handling

import { isAuthError, AuthErrorCode } from 'diksuchi-onelink';

try {
  await auth.login();
} catch (error) {
  if (isAuthError(error)) {
    switch (error.code) {
      case AuthErrorCode.TOKEN_EXPIRED:
        // Handle expired token
        break;
      case AuthErrorCode.UNAUTHORIZED:
        // Handle unauthorized
        break;
      default:
        console.error(error.message);
    }
  }
}

🌟 Examples

Complete Next.js App

// app/layout.tsx
import { DiksuchiAuthProvider } from 'diksuchi-onelink/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <DiksuchiAuthProvider
          config={{ clientId: 'projectshub' }}
          autoHandleCallback={true}
        >
          {children}
        </DiksuchiAuthProvider>
      </body>
    </html>
  );
}

// app/page.tsx
import { useAuth, LoginButton, LogoutButton } from 'diksuchi-onelink/react';

export default function Home() {
  const { user, isAuthenticated } = useAuth();

  if (!isAuthenticated) {
    return <LoginButton>Sign In</LoginButton>;
  }

  return (
    <div>
      <h1>Welcome {user?.name}!</h1>
      <LogoutButton>Sign Out</LogoutButton>
    </div>
  );
}

// app/api/data/route.ts
import { createNextAuthMiddleware } from 'diksuchi-onelink/server';

const withAuth = createNextAuthMiddleware();

export const GET = withAuth(async (request, user) => {
  return Response.json({ data: 'Protected data', user });
});

📄 License

MIT © Diksuchi EdTech


🤝 Support


🎉 Related Packages


Made with ❤️ by Diksuchi EdTech