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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@jmndao/auth-flow

v2.2.0

Published

Simple, clean authentication flow for client-side applications with automatic token management

Downloads

24

Readme

AuthFlow

Simple, clean authentication flow with separated permission system for client-side applications.

Features

  • JWT access + refresh token authentication
  • Automatic token refresh on expiration
  • Clean separation between authentication and permissions
  • Component-wrappable permission system
  • Custom validation support
  • Lightweight with zero dependencies
  • Client-side focused

Installation

npm install @jmndao/auth-flow

Architecture

AuthFlow uses a clean separation of concerns:

  • Auth: Handles authentication (login, logout, token management)
  • Permissions: Handles authorization (roles, permissions, guards)

Quick Start

import { createAuthFlow, Permissions } from '@jmndao/auth-flow';

// Create auth instance
const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
});

// Login
await auth.login({
  email: '[email protected]',
  password: 'password',
});

// Make authenticated requests
const profile = await auth.get('/user/profile');

// Check authentication (token validity)
if (auth.isAuthenticated()) {
  console.log('User is authenticated');
}

// Create permission checker
const permissions = Permissions.createPermissionChecker(auth);

// Check permissions separately
if (permissions.hasRole('admin')) {
  console.log('User is admin');
}

if (permissions.hasPermission('posts:write')) {
  console.log('User can write posts');
}

Authentication with Custom Validation

Configuration-Based Custom Validation

const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
  validateAuth: (tokens) => {
    // Custom business logic
    if (!tokens) return false;

    // Example: Check if user is in working hours
    const now = new Date();
    const isWorkingHours = now.getHours() >= 9 && now.getHours() < 17;

    return isWorkingHours && customBusinessLogic(tokens);
  },
});

// Uses custom validator
auth.isAuthenticated();

Parameter-Based Override

const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
  validateAuth: () => false, // Config always denies
});

// Default behavior (uses config)
auth.isAuthenticated(); // false

// Override with parameter
auth.isAuthenticated(() => true); // true
auth.isAuthenticated(customValidator);

Using Permission Validators in Auth

const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
  // Use permission validator as auth validator
  validateAuth: Permissions.RBAC.requireRole('admin'),
});

// Only admin users will be considered "authenticated"
auth.isAuthenticated();

Permission System

Permission Checker

const permissions = Permissions.createPermissionChecker(auth);

// Role checks
permissions.hasRole('admin');
permissions.hasAnyRole('admin', 'moderator');
permissions.hasAllRoles('editor', 'reviewer');

// Permission checks
permissions.hasPermission('posts:write');
permissions.hasAnyPermission('posts:read', 'posts:write');
permissions.hasAllPermissions('posts:write', 'posts:publish');

// Attribute checks
permissions.hasAttribute('department', 'engineering');

// Get raw claims
const claims = permissions.getClaims();

// Custom validation
permissions.check((tokens) => customLogic(tokens));

Permission Validators

Use as standalone validators or in auth configuration:

// RBAC validators
const adminValidator = Permissions.RBAC.requireRole('admin');
const editorValidator = Permissions.RBAC.requireAnyRole('editor', 'author');

// ABAC validators
const writeValidator = Permissions.ABAC.requirePermission('posts:write');
const deptValidator = Permissions.ABAC.create({
  rules: [Permissions.Rules.inDepartment('engineering')],
  mode: 'all',
});

// Combine validators
const complexValidator = Permissions.combineValidators(adminValidator, writeValidator, (tokens) =>
  customBusinessLogic(tokens)
);

// Use in auth
const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
  validateAuth: complexValidator,
});

Component Guards

Create framework-specific permission guards:

// React example
const RequireRole = Permissions.createRoleGuard((hasRole, children, fallback) => {
  return hasRole ? children : (fallback || null);
});

const RequirePermission = Permissions.createPermissionGrantGuard((hasPermission, children, fallback) => {
  return hasPermission ? children : (fallback || null);
});

// Usage in components
function AdminPanel() {
  return (
    <RequireRole
      auth={auth}
      role="admin"
      fallback={<AccessDenied />}
      onDenied={() => console.log('Access denied')}
    >
      <AdminContent />
    </RequireRole>
  );
}

function PostEditor() {
  return (
    <RequirePermission
      auth={auth}
      permission="posts:write"
      fallback={<ReadOnlyView />}
    >
      <EditForm />
    </RequirePermission>
  );
}

Combining Auth and Permissions

Flexible Validation Patterns

const auth = createAuthFlow({
  baseURL: 'https://api.example.com',
  validateAuth: (tokens) => {
    // Base business logic validation
    return tokens !== null && isWorkingHours();
  },
});

const permissions = Permissions.createPermissionChecker(auth);

// Different validation levels
if (auth.isAuthenticated()) {
  // User passes business logic validation
}

if (auth.isAuthenticated(Permissions.RBAC.requireRole('admin'))) {
  // User passes business logic AND has admin role
}

if (permissions.hasRole('admin')) {
  // User has admin role (independent of auth validation)
}

// Complex combined validation
const isSeniorManager = (tokens) => {
  const roleCheck = Permissions.RBAC.requireRole('manager')(tokens);
  const attrCheck = permissions.hasAttribute('level', 'senior');
  const businessCheck = customBusinessLogic(tokens);

  return roleCheck && attrCheck && businessCheck;
};

if (auth.isAuthenticated(isSeniorManager)) {
  // Senior manager with business logic validation
}

API Reference

Auth Methods

  • auth.login(credentials) - Authenticate user
  • auth.logout() - Log out and clear tokens
  • auth.isAuthenticated(validator?) - Check authentication
  • auth.getTokens() - Get stored tokens
  • auth.setTokens(tokens) - Set tokens manually
  • auth.get/post/put/patch/delete(url, data?, config?) - HTTP methods

Permission Methods

  • permissions.hasRole(role) - Check single role
  • permissions.hasAnyRole(...roles) - Check any role
  • permissions.hasAllRoles(...roles) - Check all roles
  • permissions.hasPermission(permission) - Check single permission
  • permissions.hasAnyPermission(...permissions) - Check any permission
  • permissions.hasAllPermissions(...permissions) - Check all permissions
  • permissions.hasAttribute(key, value) - Check attribute value
  • permissions.getClaims() - Get JWT claims
  • permissions.check(validator) - Custom validation

Validators

  • Permissions.RBAC.requireRole(role) - Role validator
  • Permissions.RBAC.requireAnyRole(...roles) - Any role validator
  • Permissions.RBAC.requireAllRoles(...roles) - All roles validator
  • Permissions.ABAC.requirePermission(permission) - Permission validator
  • Permissions.ABAC.create(config) - Custom ABAC validator
  • Permissions.combineValidators(...validators) - Combine multiple

JWT Token Structure

Expected JWT payload structure:

{
  "sub": "user123",
  "roles": ["admin", "user"],
  "permissions": ["posts:read", "posts:write"],
  "department": "engineering",
  "level": "senior",
  "exp": 1640995200
}

License

MIT