{"id":27636944,"url":"https://github.com/theriturajps/itoken","last_synced_at":"2026-02-26T12:02:17.914Z","repository":{"id":288394268,"uuid":"962045403","full_name":"theriturajps/itoken","owner":"theriturajps","description":"iToken is a robust Node.js library for token-based authentication inspired by JWT","archived":false,"fork":false,"pushed_at":"2025-04-07T15:05:33.000Z","size":9,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-11T07:25:24.377Z","etag":null,"topics":["auth0","authentication","authorization","itoken","jwt-authentication","nodejs","theriturajps","token-based-authentication"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/itoken","language":"JavaScript","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/theriturajps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2025-04-07T15:05:26.000Z","updated_at":"2025-04-07T15:09:25.000Z","dependencies_parsed_at":"2025-04-20T07:36:08.954Z","dependency_job_id":null,"html_url":"https://github.com/theriturajps/itoken","commit_stats":null,"previous_names":["theriturajps/itoken"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/theriturajps/itoken","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theriturajps%2Fitoken","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theriturajps%2Fitoken/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theriturajps%2Fitoken/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theriturajps%2Fitoken/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theriturajps","download_url":"https://codeload.github.com/theriturajps/itoken/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theriturajps%2Fitoken/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29858461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["auth0","authentication","authorization","itoken","jwt-authentication","nodejs","theriturajps","token-based-authentication"],"created_at":"2025-04-23T21:15:31.134Z","updated_at":"2026-02-26T12:02:17.816Z","avatar_url":"https://github.com/theriturajps.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# iToken\n\n[![npm version](https://img.shields.io/npm/v/itoken.svg)](https://www.npmjs.com/package/itoken)\n[![license](https://img.shields.io/npm/l/itoken.svg)](https://github.com/theriturajps/itoken/blob/main/LICENSE)\n[![node](https://img.shields.io/node/v/itoken.svg)](https://www.npmjs.com/package/itoken)\n\n`iToken` is a robust Node.js library for creating, verifying, and managing authentication tokens with enhanced security features. Inspired by JWT but designed for stricter security practices, it simplifies token-based authentication while prioritizing protection against tampering, expiration, and misuse.\n\n## Installation\n\nInstall the package using npm:\n\n```bash\nnpm install itoken\n```\n\nOr using yarn:\n\n```bash\nyarn add itoken\n```\n\n## Quick Start\n\n```javascript\nconst { iToken } = require('itoken');\n\n// Create a token\nconst payload = { userId: '123', role: 'admin' };\nconst secret = 'your-secure-secret-key';\nconst token = iToken.encode(payload, secret, { expiresIn: '1h' });\n\n// Verify and decode a token\ntry {\n  const decoded = iToken.decode(token, secret);\n  console.log(decoded.payload); // { userId: '123', role: 'admin', iat: 1649267348, exp: 1649270948 }\n} catch (error) {\n  console.error('Token validation failed:', error.message);\n}\n\n// Simple verification (returns boolean)\nconst isValid = iToken.verify(token, secret);\n```\n\n## API Reference\n\n### iToken.encode(payload, secret, options)\n\nCreates a signed token.\n\n**Parameters:**\n- **payload** `\u003cObject\u003e`: The data to encode (must be a plain object)\n- **secret** `\u003cString\u003e`: The secret key used for signing (minimum 8 characters)\n- **options** `\u003cObject\u003e` (optional):\n  - **expiresIn** `\u003cString|Number\u003e`: Token expiration time (e.g., '1h', '7d', or seconds)\n  - **notBefore** `\u003cString|Number\u003e`: Time before which the token is not valid\n  - **issuer** `\u003cString\u003e`: Token issuer identifier (iss claim)\n  - **subject** `\u003cString\u003e`: Token subject identifier (sub claim)\n  - **audience** `\u003cString\u003e`: Token audience identifier (aud claim)\n  - **header** `\u003cObject\u003e`: Additional header values to include\n\n**Returns:** `\u003cString\u003e` - A signed iToken token string.\n\n**Example:**\n```javascript\n// Creating a token that expires in 1 hour with custom claims\nconst token = iToken.encode(\n  { userId: '123', role: 'admin' },\n  'your-secret-key',\n  { \n    expiresIn: '1h',\n    issuer: 'api.example.com',\n    audience: 'client-app'\n  }\n);\n```\n\n### iToken.decode(token, secret, options)\n\nVerifies and decodes a token.\n\n**Parameters:**\n- **token** `\u003cString\u003e`: The token to decode\n- **secret** `\u003cString\u003e`: The secret key used for signing\n- **options** `\u003cObject\u003e` (optional):\n  - **skipTimeValidation** `\u003cBoolean\u003e`: Skip expiration and notBefore validation\n  - **ignoreExpiration** `(Boolean)`: Bypass expiration check\n  - **ignoreNotBefore** `(Boolean)`: Bypass activation check\n\n**Returns:** `\u003cObject\u003e` - An object with `header`, `payload`, and `signature` properties.\n\n**Example:**\n```javascript\ntry {\n  const { header, payload, signature } = iToken.decode(token, 'your-secret-key');\n  console.log(`User ID: ${payload.userId}, Role: ${payload.role}`);\n  console.log(`Token was issued at: ${new Date(payload.iat * 1000)}`);\n  console.log(`Token expires at: ${new Date(payload.exp * 1000)}`);\n} catch (error) {\n  console.error(`Decoding error: ${error.message}`);\n}\n```\n\n### iToken.verify(token, secret, options)\n\nQuick validation without returning the decoded data.\n\n**Parameters:**\n- **token** `\u003cString\u003e`: The token to verify\n- **secret** `\u003cString\u003e`: The secret key used for signing\n- **options** `\u003cObject\u003e` (optional):\n  - **ignoreExpiration** `\u003cBoolean\u003e`: Ignore expiration time validation\n  - **ignoreNotBefore** `\u003cBoolean\u003e`: Ignore notBefore time validation\n\n**Returns:** `\u003cBoolean\u003e` - `true` if the token is valid, otherwise `false`.\n\n**Example:**\n```javascript\n// Standard verification - checks signature, expiration, and notBefore claims\nif (iToken.verify(token, 'your-secret-key')) {\n  console.log('Token is valid');\n} else {\n  console.log('Token is invalid');\n}\n\n// Verification with options - ignore expiration\nif (iToken.verify(token, 'your-secret-key', { ignoreExpiration: true })) {\n  console.log('Token signature is valid (ignoring expiration)');\n}\n```\n\n### iToken.refresh(token, secret, newOptions)\n\nRefreshes an existing token with same payload but fresh timestamps.\n\n**Parameters:**\n- **token** `\u003cString\u003e`: The token to refresh\n- **secret** `\u003cString\u003e`: The secret key used for signing\n- **newOptions** `\u003cObject\u003e` (optional): New options for the refreshed token\n\n**Returns:** `\u003cString\u003e` - A new token string with updated options.\n\n**Example:**\n```javascript\n// Refreshing an expired token with new expiration time\nconst refreshedToken = iToken.refresh(\n  oldToken,\n  'your-secret-key',\n  { \n    expiresIn: '2h',\n    audience: 'updated-client-app' \n  }\n);\n```\n\n## Token Structure\n\nEach iToken token consists of three parts separated by periods:\n\n```\n[header].[payload].[signature]\n```\n\n1. **Header**: Contains metadata about the token (base64url encoded JSON)\n   - `alg`: Algorithm used for signing (default: \"HS256\")\n   - `typ`: Token type identifier (default: \"AEG1\")\n   - Any custom header fields provided in options\n\n2. **Payload**: Contains the claims (base64url encoded JSON)\n   - Custom claims (user data)\n   - Standard claims (iat, exp, nbf, iss, aud, sub)\n\n3. **Signature**: HMAC-SHA256 hash of the header and payload using the secret key\n\n## Standard Claims\n\niToken automatically handles these standard claims:\n\n| Claim | Name | Description |\n|-------|------|-------------|\n| `iat` | Issued At | Timestamp when the token was created (automatically added) |\n| `exp` | Expiration Time | Timestamp when the token expires (added when `expiresIn` option is used) |\n| `nbf` | Not Before | Timestamp before which the token is not valid (added when `notBefore` option is used) |\n| `iss` | Issuer | Identifies who issued the token (added when `issuer` option is used) |\n| `aud` | Audience | Identifies the recipients of the token (added when `audience` option is used) |\n| `sub` | Subject | Identifies the subject of the token (added when `subject` option is used) |\n\n## Error Handling\n\niToken provides specific error types for different validation scenarios:\n\n```javascript\nconst {\n  iToken, \n  iTokenError,            // Base error type\n  iTokenExpiredError,     // Token has expired\n  iTokenNotBeforeError,   // Token is not yet valid\n  iTokenTamperError,      // Token signature validation failed\n  iTokenValidationError,  // Token payload or options validation failed\n  iTokenFormatError       // Token format is invalid\n} = require('itoken');\n\ntry {\n  const decoded = iToken.decode(token, secret);\n  // Token is valid\n} catch (error) {\n  if (error instanceof iTokenExpiredError) {\n    console.log(`Token expired at: ${new Date(error.expiredAt * 1000)}`);\n  } else if (error instanceof iTokenNotBeforeError) {\n    console.log(`Token not valid until: ${new Date(error.notBefore * 1000)}`);\n  } else if (error instanceof iTokenTamperError) {\n    console.log('Token signature verification failed - possible tampering detected');\n  } else if (error instanceof iTokenValidationError) {\n    console.log('Token validation error:', error.message);\n  } else if (error instanceof iTokenFormatError) {\n    console.log('Token format error:', error.message);\n  } else {\n    console.log('Unknown error:', error.message);\n  }\n}\n```\n\n## Working Examples\n\n### API Access Token\n\n```javascript\nconst { iToken } = require('itoken');\n\nconst token = iToken.encode(\n  { userId: 456 },\n  SECRET,\n  {\n    issuer: 'api-server',\n    audience: 'mobile-app',\n    expiresIn: '30m',\n    notBefore: '5s' // Prevent immediate use\n  }\n);\n```\n\n### Scheduled Maintenance Token\n\n```javascript\nconst { iToken } = require('itoken');\n\n// Valid during maintenance window (next 2 hours)\nconst maintenanceStart = Math.floor(Date.now() / 1000) + 3600; // 1h from now\nconst token = iToken.encode(\n  { access: 'maintenance' },\n  SECRET,\n  {\n    notBefore: maintenanceStart,\n    expiresIn: 7200 // 2h\n  }\n);\n```\n\n### Refresh Token Flow\n\n```javascript\nconst { iToken } = require('itoken');\n\n// Create long-lived refresh token\nconst refreshToken = iToken.encode(\n  { userId: 789 },\n  SECRET,\n  { expiresIn: '7d' }\n);\n\n// Refresh when access token expires\nfunction refreshAccess(oldToken) {\n  return iToken.refresh(oldToken, SECRET, { expiresIn: '1h' });\n}\n```\n\n### Basic Authentication\n\n```javascript\nconst { iToken } = require('itoken');\n\n// User login function\nfunction login(username, password) {\n  // In a real app, verify credentials against a database\n  if (username === 'user@example.com' \u0026\u0026 password === 'correct-password') {\n    // Create a user object (excluding sensitive info)\n    const user = {\n      id: 'user-123',\n      email: username,\n      name: 'John Doe'\n    };\n    \n    // Create a token that expires in 24 hours\n    const token = iToken.encode(\n      user, \n      'your-secure-key',\n      { expiresIn: '24h' }\n    );\n    \n    return { user, token };\n  }\n  \n  throw new Error('Invalid credentials');\n}\n\n// Example usage\ntry {\n  const { user, token } = login('user@example.com', 'correct-password');\n  console.log('Login successful:', user);\n  console.log('Access token:', token);\n} catch (error) {\n  console.error('Login failed:', error.message);\n}\n```\n\n### Role-Based Access Control\n\n```javascript\nconst { iToken, iTokenError } = require('itoken');\n\nconst SECRET_KEY = 'your-secure-key';\n\n// Authorization function\nfunction checkPermission(token, requiredRole) {\n  try {\n    const { payload } = iToken.decode(token, SECRET_KEY);\n    \n    // Check if user has the required role\n    if (!payload.roles || !payload.roles.includes(requiredRole)) {\n      return { authorized: false, message: 'Insufficient permissions' };\n    }\n    \n    return { authorized: true, user: payload };\n  } catch (error) {\n    if (error instanceof iTokenError) {\n      return { authorized: false, message: error.message };\n    }\n    return { authorized: false, message: 'Authorization failed' };\n  }\n}\n\n// Example token with role information\nconst adminToken = iToken.encode(\n  { \n    id: 'user-456', \n    name: 'Admin User', \n    roles: ['user', 'editor', 'admin'] \n  },\n  SECRET_KEY,\n  { expiresIn: '8h' }\n);\n\nconst editorToken = iToken.encode(\n  { \n    id: 'user-789', \n    name: 'Editor User', \n    roles: ['user', 'editor'] \n  },\n  SECRET_KEY,\n  { expiresIn: '8h' }\n);\n\n// Check permissions\nconsole.log(checkPermission(adminToken, 'admin'));   // { authorized: true, user: {...} }\nconsole.log(checkPermission(editorToken, 'admin'));  // { authorized: false, message: 'Insufficient permissions' }\n```\n\n### Token Refresh Mechanism\n\n```javascript\nconst { iToken, iTokenExpiredError } = require('itoken');\n\nconst SECRET_KEY = 'your-secure-key';\n\n// Function to get a valid token, refreshing if expired\nfunction getValidToken(currentToken) {\n  try {\n    // Try to decode the current token\n    const { payload } = iToken.decode(currentToken, SECRET_KEY);\n    return { valid: true, token: currentToken, payload };\n  } catch (error) {\n    // Check if token is expired\n    if (error instanceof iTokenExpiredError) {\n      try {\n        // Refresh the token with a new expiration time\n        const newToken = iToken.refresh(currentToken, SECRET_KEY, { expiresIn: '1h' });\n        const { payload } = iToken.decode(newToken, SECRET_KEY);\n        return { valid: true, token: newToken, payload, refreshed: true };\n      } catch (refreshError) {\n        return { valid: false, error: 'Could not refresh token: ' + refreshError.message };\n      }\n    }\n    \n    return { valid: false, error: error.message };\n  }\n}\n\n// Example usage\nconst originalToken = iToken.encode({ userId: '123' }, SECRET_KEY, { expiresIn: '1s' });\n\n// Wait 2 seconds for token to expire\nsetTimeout(() =\u003e {\n  const result = getValidToken(originalToken);\n  \n  if (result.valid) {\n    console.log('Token is valid' + (result.refreshed ? ' (refreshed)' : ''));\n    console.log('Current token:', result.token);\n    console.log('Payload:', result.payload);\n  } else {\n    console.error('Invalid token:', result.error);\n  }\n}, 2000);\n```\n\n### Express Middleware Integration\n\n```javascript\nconst express = require('express');\nconst { iToken, iTokenError } = require('itoken');\n\nconst app = express();\napp.use(express.json());\n\nconst SECRET_KEY = 'your-secure-key';\n\n// Authentication middleware\nfunction authenticate(req, res, next) {\n  // Get authorization header\n  const authHeader = req.headers.authorization;\n  \n  // Check if header exists and has the right format\n  if (!authHeader || !authHeader.startsWith('Bearer ')) {\n    return res.status(401).json({ \n      error: 'Authentication required',\n      details: 'Missing or invalid authorization header'\n    });\n  }\n  \n  // Extract token\n  const token = authHeader.split(' ')[1];\n  \n  try {\n    // Verify and decode token\n    const { payload } = iToken.decode(token, SECRET_KEY);\n    \n    // Attach user info to the request object\n    req.user = payload;\n    \n    // Continue to the route handler\n    next();\n  } catch (error) {\n    // Handle specific errors\n    if (error instanceof iTokenError) {\n      let statusCode = 401;\n      let errorType = 'authentication_failed';\n      \n      if (error.name === 'iTokenExpiredError') {\n        errorType = 'token_expired';\n      } else if (error.name === 'iTokenNotBeforeError') {\n        errorType = 'token_not_active';\n      } else if (error.name === 'iTokenTamperError') {\n        statusCode = 403;\n        errorType = 'token_invalid';\n      }\n      \n      return res.status(statusCode).json({\n        error: errorType,\n        details: error.message\n      });\n    }\n    \n    // Handle unexpected errors\n    return res.status(500).json({\n      error: 'internal_error',\n      details: 'Authentication process failed'\n    });\n  }\n}\n\n// Role-based authorization middleware factory\nfunction authorize(requiredRole) {\n  return (req, res, next) =\u003e {\n    // Check if user exists (authenticate middleware should run first)\n    if (!req.user) {\n      return res.status(401).json({\n        error: 'authentication_required',\n        details: 'You must be logged in'\n      });\n    }\n    \n    // Check if user has the required role\n    if (!req.user.roles || !req.user.roles.includes(requiredRole)) {\n      return res.status(403).json({\n        error: 'insufficient_permissions',\n        details: `Role '${requiredRole}' is required`\n      });\n    }\n    \n    // User has the required role, proceed\n    next();\n  };\n}\n\n// Login endpoint\napp.post('/login', (req, res) =\u003e {\n  const { username, password } = req.body;\n  \n  // Simple user verification (replace with database lookup in real app)\n  let user;\n  \n  if (username === 'admin@example.com' \u0026\u0026 password === 'admin123') {\n    user = { id: '1', username, name: 'Admin User', roles: ['user', 'admin'] };\n  } else if (username === 'user@example.com' \u0026\u0026 password === 'user123') {\n    user = { id: '2', username, name: 'Regular User', roles: ['user'] };\n  } else {\n    return res.status(401).json({ error: 'Invalid credentials' });\n  }\n  \n  // Create token\n  const token = iToken.encode(\n    user,\n    SECRET_KEY,\n    { \n      expiresIn: '1h',\n      issuer: 'api.example.com'\n    }\n  );\n  \n  // Return user info and token\n  res.json({\n    message: 'Login successful',\n    user: {\n      id: user.id,\n      name: user.name,\n      roles: user.roles\n    },\n    token,\n    expiresIn: 3600 // seconds\n  });\n});\n\n// Protected route - requires authentication\napp.get('/profile', authenticate, (req, res) =\u003e {\n  res.json({\n    message: 'Profile accessed successfully',\n    user: req.user\n  });\n});\n\n// Admin route - requires authentication and admin role\napp.get('/admin/dashboard', authenticate, authorize('admin'), (req, res) =\u003e {\n  res.json({\n    message: 'Admin dashboard accessed successfully',\n    adminData: {\n      users: 1045,\n      newToday: 27,\n      activeNow: 165\n    }\n  });\n});\n\n// Public endpoint - no authentication required\napp.get('/public', (req, res) =\u003e {\n  res.json({ message: 'This is public information' });\n});\n\n// Start server\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () =\u003e {\n  console.log(`Server running on port ${PORT}`);\n});\n```\n\n## Security Best Practices 🔐\n\nFollow these security recommendations when working with iToken tokens:\n\n1. **Use strong secrets**: Minimum 32 random characters\n2. **Set reasonable expiration**: Typically 15-60 minutes\n3. **Validate all claims**:\n   ```javascript\n   const { payload } = iToken.decode(token, SECRET);\n   if (payload.aud !== 'api.example.com') throw new Error('Invalid audience');\n   ```\n4. **Always use HTTPS** for token transmission\n5. **Rotate secrets** regularly\n\n## Comparing iToken vs JWT\n\n| Feature | iToken | Traditional JWT |\n|---------|--------|-----------------|\n| **Token Type** | Uses \"AEG1\" type identifier | Uses \"JWT\" type identifier |\n| **Error Handling** | Provides specific error types | Generic errors in most libraries |\n| **Time Validation** | Built-in expiration and notBefore handling | Varies by library |\n| **Signature Verification** | Timing-safe comparison by default | Varies by library |\n| **API** | Streamlined, focused API | Often more complex |\n| **Refresh Mechanism** | Built-in token refresh | Usually requires custom implementation |\n\n## TypeScript Support\n\niToken provides TypeScript definitions for better integration with TypeScript projects:\n\n```typescript\nimport { iToken, iTokenError } from 'itoken';\n\ninterface UserPayload {\n  id: string;\n  username: string;\n  roles: string[];\n}\n\n// Create a token with typed payload\nconst payload: UserPayload = {\n  id: '123',\n  username: 'user@example.com',\n  roles: ['user', 'editor']\n};\n\nconst token = iToken.encode(payload, 'secret', { expiresIn: '1h' });\n\ntry {\n  // Decoded payload will have UserPayload type plus standard claims\n  const { payload } = iToken.decode\u003cUserPayload\u003e(token, 'secret');\n  \n  // TypeScript knows about these properties\n  console.log(payload.id);\n  console.log(payload.roles);\n  console.log(payload.iat); // Standard claim\n} catch (error) {\n  if (error instanceof iTokenError) {\n    console.error('iToken error:', error.message);\n  }\n}\n```\n\n## FAQ ❓\n\n**Q: How is this different from JWT?**  \nA: Focuses on identity security with stricter defaults and zero dependencies.\n\n**Q: Can I use existing JWT tokens?**  \nA: No - iToken uses `AEG1` token format for enhanced security.\n\n**Q: Is this production-ready?**  \nA: Yes! Follows Node.js crypto best practices.\n\n**Q: How to handle clock skew?**  \nA: Add buffer to expiration times:\n```javascript\niToken.encode(payload, SECRET, { expiresIn: 3600 + 300 }); // 1h + 5m buffer\n```\n\n---\n\n**License**: MIT | **Author**: [Ritu Raj Pratap Singh](https://github.com/theriturajps)  \n**GitHub**: [github.com/theriturajps/itoken](https://github.com/theriturajps/itoken)  \n**Report Issues**: [Issues](https://github.com/theriturajps/itoken/issues)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheriturajps%2Fitoken","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheriturajps%2Fitoken","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheriturajps%2Fitoken/lists"}