{"id":49501477,"url":"https://github.com/jmndao/auth-flow","last_synced_at":"2026-05-01T12:49:36.883Z","repository":{"id":302162751,"uuid":"1011496615","full_name":"jmndao/auth-flow","owner":"jmndao","description":"Simple, clean authentication flow for client-side applications with automatic token management","archived":false,"fork":false,"pushed_at":"2025-09-19T21:15:35.000Z","size":465,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-01T12:49:33.658Z","etag":null,"topics":["auth","auth-flow","authentication","client","enterprise","jwt","login","production-ready","react","server","session","token"],"latest_commit_sha":null,"homepage":"https://auth-flow-virid.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jmndao.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-30T23:10:41.000Z","updated_at":"2025-11-10T11:05:33.000Z","dependencies_parsed_at":"2025-06-30T23:21:22.523Z","dependency_job_id":"b6c5b692-d1fd-428b-9e11-89be460c7e70","html_url":"https://github.com/jmndao/auth-flow","commit_stats":null,"previous_names":["jmndao/auth-flow"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/jmndao/auth-flow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmndao%2Fauth-flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmndao%2Fauth-flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmndao%2Fauth-flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmndao%2Fauth-flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmndao","download_url":"https://codeload.github.com/jmndao/auth-flow/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmndao%2Fauth-flow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32497815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auth","auth-flow","authentication","client","enterprise","jwt","login","production-ready","react","server","session","token"],"created_at":"2026-05-01T12:49:35.469Z","updated_at":"2026-05-01T12:49:36.868Z","avatar_url":"https://github.com/jmndao.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AuthFlow\n\nSimple, clean authentication flow with separated permission system for client-side applications.\n\n## Features\n\n- JWT access + refresh token authentication\n- Automatic token refresh on expiration\n- Clean separation between authentication and permissions\n- Component-wrappable permission system\n- Custom validation support\n- Lightweight with zero dependencies\n- Client-side focused\n\n## Installation\n\n```bash\nnpm install @jmndao/auth-flow\n```\n\n## Architecture\n\nAuthFlow uses a clean separation of concerns:\n\n- **Auth**: Handles authentication (login, logout, token management)\n- **Permissions**: Handles authorization (roles, permissions, guards)\n\n## Quick Start\n\n```typescript\nimport { createAuthFlow, Permissions } from '@jmndao/auth-flow';\n\n// Create auth instance\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n});\n\n// Login\nawait auth.login({\n  email: 'user@example.com',\n  password: 'password',\n});\n\n// Make authenticated requests\nconst profile = await auth.get('/user/profile');\n\n// Check authentication (token validity)\nif (auth.isAuthenticated()) {\n  console.log('User is authenticated');\n}\n\n// Create permission checker\nconst permissions = Permissions.createPermissionChecker(auth);\n\n// Check permissions separately\nif (permissions.hasRole('admin')) {\n  console.log('User is admin');\n}\n\nif (permissions.hasPermission('posts:write')) {\n  console.log('User can write posts');\n}\n```\n\n## Authentication with Custom Validation\n\n### Configuration-Based Custom Validation\n\n```typescript\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n  validateAuth: (tokens) =\u003e {\n    // Custom business logic\n    if (!tokens) return false;\n\n    // Example: Check if user is in working hours\n    const now = new Date();\n    const isWorkingHours = now.getHours() \u003e= 9 \u0026\u0026 now.getHours() \u003c 17;\n\n    return isWorkingHours \u0026\u0026 customBusinessLogic(tokens);\n  },\n});\n\n// Uses custom validator\nauth.isAuthenticated();\n```\n\n### Parameter-Based Override\n\n```typescript\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n  validateAuth: () =\u003e false, // Config always denies\n});\n\n// Default behavior (uses config)\nauth.isAuthenticated(); // false\n\n// Override with parameter\nauth.isAuthenticated(() =\u003e true); // true\nauth.isAuthenticated(customValidator);\n```\n\n### Using Permission Validators in Auth\n\n```typescript\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n  // Use permission validator as auth validator\n  validateAuth: Permissions.RBAC.requireRole('admin'),\n});\n\n// Only admin users will be considered \"authenticated\"\nauth.isAuthenticated();\n```\n\n## Permission System\n\n### Permission Checker\n\n```typescript\nconst permissions = Permissions.createPermissionChecker(auth);\n\n// Role checks\npermissions.hasRole('admin');\npermissions.hasAnyRole('admin', 'moderator');\npermissions.hasAllRoles('editor', 'reviewer');\n\n// Permission checks\npermissions.hasPermission('posts:write');\npermissions.hasAnyPermission('posts:read', 'posts:write');\npermissions.hasAllPermissions('posts:write', 'posts:publish');\n\n// Attribute checks\npermissions.hasAttribute('department', 'engineering');\n\n// Get raw claims\nconst claims = permissions.getClaims();\n\n// Custom validation\npermissions.check((tokens) =\u003e customLogic(tokens));\n```\n\n### Permission Validators\n\nUse as standalone validators or in auth configuration:\n\n```typescript\n// RBAC validators\nconst adminValidator = Permissions.RBAC.requireRole('admin');\nconst editorValidator = Permissions.RBAC.requireAnyRole('editor', 'author');\n\n// ABAC validators\nconst writeValidator = Permissions.ABAC.requirePermission('posts:write');\nconst deptValidator = Permissions.ABAC.create({\n  rules: [Permissions.Rules.inDepartment('engineering')],\n  mode: 'all',\n});\n\n// Combine validators\nconst complexValidator = Permissions.combineValidators(adminValidator, writeValidator, (tokens) =\u003e\n  customBusinessLogic(tokens)\n);\n\n// Use in auth\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n  validateAuth: complexValidator,\n});\n```\n\n### Component Guards\n\nCreate framework-specific permission guards:\n\n```typescript\n// React example\nconst RequireRole = Permissions.createRoleGuard((hasRole, children, fallback) =\u003e {\n  return hasRole ? children : (fallback || null);\n});\n\nconst RequirePermission = Permissions.createPermissionGrantGuard((hasPermission, children, fallback) =\u003e {\n  return hasPermission ? children : (fallback || null);\n});\n\n// Usage in components\nfunction AdminPanel() {\n  return (\n    \u003cRequireRole\n      auth={auth}\n      role=\"admin\"\n      fallback={\u003cAccessDenied /\u003e}\n      onDenied={() =\u003e console.log('Access denied')}\n    \u003e\n      \u003cAdminContent /\u003e\n    \u003c/RequireRole\u003e\n  );\n}\n\nfunction PostEditor() {\n  return (\n    \u003cRequirePermission\n      auth={auth}\n      permission=\"posts:write\"\n      fallback={\u003cReadOnlyView /\u003e}\n    \u003e\n      \u003cEditForm /\u003e\n    \u003c/RequirePermission\u003e\n  );\n}\n```\n\n## Combining Auth and Permissions\n\n### Flexible Validation Patterns\n\n```typescript\nconst auth = createAuthFlow({\n  baseURL: 'https://api.example.com',\n  validateAuth: (tokens) =\u003e {\n    // Base business logic validation\n    return tokens !== null \u0026\u0026 isWorkingHours();\n  },\n});\n\nconst permissions = Permissions.createPermissionChecker(auth);\n\n// Different validation levels\nif (auth.isAuthenticated()) {\n  // User passes business logic validation\n}\n\nif (auth.isAuthenticated(Permissions.RBAC.requireRole('admin'))) {\n  // User passes business logic AND has admin role\n}\n\nif (permissions.hasRole('admin')) {\n  // User has admin role (independent of auth validation)\n}\n\n// Complex combined validation\nconst isSeniorManager = (tokens) =\u003e {\n  const roleCheck = Permissions.RBAC.requireRole('manager')(tokens);\n  const attrCheck = permissions.hasAttribute('level', 'senior');\n  const businessCheck = customBusinessLogic(tokens);\n\n  return roleCheck \u0026\u0026 attrCheck \u0026\u0026 businessCheck;\n};\n\nif (auth.isAuthenticated(isSeniorManager)) {\n  // Senior manager with business logic validation\n}\n```\n\n## API Reference\n\n### Auth Methods\n\n- `auth.login(credentials)` - Authenticate user\n- `auth.logout()` - Log out and clear tokens\n- `auth.isAuthenticated(validator?)` - Check authentication\n- `auth.getTokens()` - Get stored tokens\n- `auth.setTokens(tokens)` - Set tokens manually\n- `auth.get/post/put/patch/delete(url, data?, config?)` - HTTP methods\n\n### Permission Methods\n\n- `permissions.hasRole(role)` - Check single role\n- `permissions.hasAnyRole(...roles)` - Check any role\n- `permissions.hasAllRoles(...roles)` - Check all roles\n- `permissions.hasPermission(permission)` - Check single permission\n- `permissions.hasAnyPermission(...permissions)` - Check any permission\n- `permissions.hasAllPermissions(...permissions)` - Check all permissions\n- `permissions.hasAttribute(key, value)` - Check attribute value\n- `permissions.getClaims()` - Get JWT claims\n- `permissions.check(validator)` - Custom validation\n\n### Validators\n\n- `Permissions.RBAC.requireRole(role)` - Role validator\n- `Permissions.RBAC.requireAnyRole(...roles)` - Any role validator\n- `Permissions.RBAC.requireAllRoles(...roles)` - All roles validator\n- `Permissions.ABAC.requirePermission(permission)` - Permission validator\n- `Permissions.ABAC.create(config)` - Custom ABAC validator\n- `Permissions.combineValidators(...validators)` - Combine multiple\n\n## JWT Token Structure\n\nExpected JWT payload structure:\n\n```json\n{\n  \"sub\": \"user123\",\n  \"roles\": [\"admin\", \"user\"],\n  \"permissions\": [\"posts:read\", \"posts:write\"],\n  \"department\": \"engineering\",\n  \"level\": \"senior\",\n  \"exp\": 1640995200\n}\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmndao%2Fauth-flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmndao%2Fauth-flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmndao%2Fauth-flow/lists"}