Simple, clean authentication flow with separated permission system for client-side applications.
- 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
npm install @jmndao/auth-flowAuthFlow uses a clean separation of concerns:
- Auth: Handles authentication (login, logout, token management)
- Permissions: Handles authorization (roles, permissions, guards)
import { createAuthFlow, Permissions } from '@jmndao/auth-flow';
// Create auth instance
const auth = createAuthFlow({
baseURL: 'https://api.example.com',
});
// Login
await auth.login({
email: 'user@example.com',
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');
}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();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);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();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));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,
});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>
);
}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
}auth.login(credentials)- Authenticate userauth.logout()- Log out and clear tokensauth.isAuthenticated(validator?)- Check authenticationauth.getTokens()- Get stored tokensauth.setTokens(tokens)- Set tokens manuallyauth.get/post/put/patch/delete(url, data?, config?)- HTTP methods
permissions.hasRole(role)- Check single rolepermissions.hasAnyRole(...roles)- Check any rolepermissions.hasAllRoles(...roles)- Check all rolespermissions.hasPermission(permission)- Check single permissionpermissions.hasAnyPermission(...permissions)- Check any permissionpermissions.hasAllPermissions(...permissions)- Check all permissionspermissions.hasAttribute(key, value)- Check attribute valuepermissions.getClaims()- Get JWT claimspermissions.check(validator)- Custom validation
Permissions.RBAC.requireRole(role)- Role validatorPermissions.RBAC.requireAnyRole(...roles)- Any role validatorPermissions.RBAC.requireAllRoles(...roles)- All roles validatorPermissions.ABAC.requirePermission(permission)- Permission validatorPermissions.ABAC.create(config)- Custom ABAC validatorPermissions.combineValidators(...validators)- Combine multiple
Expected JWT payload structure:
{
"sub": "user123",
"roles": ["admin", "user"],
"permissions": ["posts:read", "posts:write"],
"department": "engineering",
"level": "senior",
"exp": 1640995200
}MIT