{"_id":"@dax-side/jwt-abstraction","_rev":"9-a7d53bdcb9df46d22e20e9267e82fd2a","name":"@dax-side/jwt-abstraction","dist-tags":{"latest":"0.2.6"},"versions":{"0.1.0":{"name":"@dax-side/jwt-abstraction","version":"0.1.0","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.1.0","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://github.com/damola/jwt-abstraction#readme","bugs":{"url":"https://github.com/damola/jwt-abstraction/issues"},"dist":{"shasum":"b203b8a3260d062f6c7f563fb6e2b0d67b956264","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.1.0.tgz","fileCount":30,"integrity":"sha512-2umTRmFKMyQsf79rGh61MiiitPH7gu5vx7shxq02CWmVHbUnT9ESopLPscvG7xWqeExguvLmIhwJRQ/CuGu6cA==","signatures":[{"sig":"MEUCICj2MiLwx21xkTwEbj4yEUGSjwtBLa6TBSmKrO72KevOAiEAo6Gajor9jDvjS32bHyD+aBfKuq8i5W0ob8CvD+VBHKg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40680},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/damola/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"JWT authentication that works out of the box. Secure defaults, Express middleware, full TypeScript support.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^4.0.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.1.0_1769677477731_0.5626675429574333","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@dax-side/jwt-abstraction","version":"0.2.1","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.2.1","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://github.com/damola/jwt-abstraction#readme","bugs":{"url":"https://github.com/damola/jwt-abstraction/issues"},"dist":{"shasum":"2eac596400e86bd2ade096a23738a93e227815dd","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.1.tgz","fileCount":30,"integrity":"sha512-CZvwRhf5xSqlTG/PReF8grPEtzEHEr9bSPM9WtZqM6/KMsNNGhQsWtjBcnaFviApM2elfcRXcv4VHVXEX6z4GQ==","signatures":[{"sig":"MEYCIQDa2wcr0KSsTSa/WP+PPyZBpuI7ykpx2xMFzrwcETdTAQIhAIiVY6ZrAYVjTNqu0Gwwtr0RaU1wPgZNZE7Dg+gZvx6m","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35133},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/damola/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2","@dax-side/jwt-abstraction":"^0.2.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^5.2.1"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.2.1_1769681331098_0.6471982888123828","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@dax-side/jwt-abstraction","version":"0.2.2","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.2.2","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://github.com/damola/jwt-abstraction#readme","bugs":{"url":"https://github.com/damola/jwt-abstraction/issues"},"dist":{"shasum":"c71f662668160b9416ed3d1a11182a9edd4ea6d7","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.2.tgz","fileCount":30,"integrity":"sha512-e2Lj89XOPRfwBhzlCTGY/5B7Zu+lwMOpMjOKPZqwiO7qRViqwxlRByPdeb748StsTmhFnf7t10ZxPrWpEnMgPg==","signatures":[{"sig":"MEUCIQDoi4c6kD4+nlmPN5Nl5PvTEn35DuwjH9iZMCWVkNlXVAIgNMbt0/pDy9prPrqbZ1gYZkTiuw2Lze8L0oCsaU1lXRk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35087},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"cc89322697bd004ffb613f26ea571729b0564e58","scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/damola/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2","@dax-side/jwt-abstraction":"^0.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^5.2.1"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.2.2_1769682416203_0.537359416426201","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@dax-side/jwt-abstraction","version":"0.2.3","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.2.3","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://github.com/damola/jwt-abstraction#readme","bugs":{"url":"https://github.com/damola/jwt-abstraction/issues"},"dist":{"shasum":"6bbcab9d1cbc8e82c678504b6a8d2a536538bdb8","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.3.tgz","fileCount":31,"integrity":"sha512-Fk7YS6+aT0936EY63ouDGsuzYpmtJIkFJIvjanV7TqvV+RUoUtbBPzDfa0eMdJwdS1TFrfQ84gwEGY/ay3lfHA==","signatures":[{"sig":"MEUCIBuwx7IrTY98dL+4q91mZfyrLlY0veSMJfMsdqlkTzlIAiEA3uBLd84FvdafkiHo6TUIvEaWHtMz/ywbuFztPnrI7GY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37558},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"febff1a063736f9956638ce576dc643fd9e90497","scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/damola/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2","@dax-side/jwt-abstraction":"^0.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^5.2.1"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.2.3_1769689045154_0.30651156311967775","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@dax-side/jwt-abstraction","version":"0.2.4","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.2.4","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://github.com/dax-side/jwt-abstraction#readme","bugs":{"url":"https://github.com/dax-side/jwt-abstraction/issues"},"dist":{"shasum":"013a894c48295057a67db35ae94d7287e7d076db","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.4.tgz","fileCount":31,"integrity":"sha512-mGfo6AUb8foTaxGOj2JfCryuh9fGQW+0VaNdgv8QY8ZD77MD9aI+dk78K6LoyDNqzBNoCXAm0D8jayJBnypw7g==","signatures":[{"sig":"MEQCIFK+ckvHoPgVpj0XRvQZxt2QzvoMi/Dkmc1BfMKdGUCgAiBVAhFUveEbeCgLBkvIxodTPOs1zVAo+EVTPGP6i/KKLg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37564},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"13f5d4f87cf4b88bc36deaf8d8693d16a4233caa","scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/dax-side/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2","@dax-side/jwt-abstraction":"^0.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^5.2.1"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.2.4_1769694011853_0.8658456548708389","host":"s3://npm-registry-packages-npm-production"}},"0.2.5":{"name":"@dax-side/jwt-abstraction","version":"0.2.5","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"author":{"name":"Damola"},"license":"MIT","_id":"@dax-side/jwt-abstraction@0.2.5","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"homepage":"https://dax-side.github.io/jwt-abstraction-site","bugs":{"url":"https://github.com/dax-side/jwt-abstraction/issues"},"dist":{"shasum":"01bff73ef1c6a9fdbc22c3acaae8a1b9135f5492","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.5.tgz","fileCount":31,"integrity":"sha512-fMZ3Sj/HHwhBNnNWSeIYSYYqN2GFGzLLDfBNfabcMPOivGYSQXkd8uiHKSou3nVwbRP6w2nWtvQkCfdO6RMbxA==","signatures":[{"sig":"MEQCICJzyOYb9Yx2/GMRPjfOr+PXQTVcS3C8CDfqDpnttpMEAiA4itTkPV4E/cUVMYqE+ngs8hSziR/o8F/wLAkYBXQqAw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37561},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"84322520a9969827244e8f4e7979271aaf74c624","scripts":{"lint":"eslint src tests --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm test && npm run build"},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"repository":{"url":"git+https://github.com/dax-side/jwt-abstraction.git","type":"git"},"_npmVersion":"10.8.2","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","directories":{},"_nodeVersion":"20.19.5","dependencies":{"jsonwebtoken":"^9.0.2","@dax-side/jwt-abstraction":"^0.2.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^5.0.6","@types/jsonwebtoken":"^9.0.5","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"peerDependencies":{"express":"^5.2.1"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jwt-abstraction_0.2.5_1770628174831_0.31062255530167837","host":"s3://npm-registry-packages-npm-production"}},"0.2.6":{"name":"@dax-side/jwt-abstraction","version":"0.2.6","description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","build":"tsc","prepublishOnly":"npm test && npm run build","lint":"eslint src tests --ext .ts","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\""},"keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"repository":{"type":"git","url":"git+https://github.com/dax-side/jwt-abstraction.git"},"bugs":{"url":"https://github.com/dax-side/jwt-abstraction/issues"},"homepage":"https://dax-side.github.io/jwt-abstraction-site","author":{"name":"Damola"},"license":"MIT","engines":{"node":">=16.0.0"},"peerDependencies":{"express":">=4.11"},"peerDependenciesMeta":{"express":{"optional":true}},"dependencies":{"jsonwebtoken":"^9.0.2"},"devDependencies":{"@types/express":"^5.0.6","@types/jest":"^29.5.11","@types/jsonwebtoken":"^9.0.5","@types/node":"^20.10.6","@typescript-eslint/eslint-plugin":"^6.17.0","@typescript-eslint/parser":"^6.17.0","eslint":"^8.56.0","jest":"^29.7.0","prettier":"^3.1.1","ts-jest":"^29.1.1","typescript":"^5.3.3"},"_id":"@dax-side/jwt-abstraction@0.2.6","gitHead":"5eacaa616a16a73a651fc58f1fa31f4863d2dea7","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-19WHri++1b08fndy4aU9esP0uEaT07SxR+OjCmcAdSvN+WM4oZTtLLzaa+39iXJjQ3CvrQz40i05JdQDeKHT/g==","shasum":"80ba355dd1ff3c53eac998322fffa3899f7d6ef9","tarball":"https://registry.npmjs.org/@dax-side/jwt-abstraction/-/jwt-abstraction-0.2.6.tgz","fileCount":31,"unpackedSize":37518,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHeiF64UKlg+9b+Djft7cSv2tvZR9E/3HD8Tr0OL2w8xAiBZack2uoZf2arV6BV8YzJGX5QZa8W+wCZ+w8+yGI+5MQ=="}]},"_npmUser":{"name":"dax-side","email":"damolaadegbite77@gmail.com"},"directories":{},"maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jwt-abstraction_0.2.6_1771349139575_0.9255432233999745"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-29T09:04:37.629Z","modified":"2026-02-17T17:25:39.844Z","0.1.0":"2026-01-29T09:04:37.884Z","0.2.0":"2026-01-29T09:47:55.564Z","0.2.1":"2026-01-29T10:08:51.260Z","0.2.2":"2026-01-29T10:26:56.333Z","0.2.3":"2026-01-29T12:17:25.345Z","0.2.4":"2026-01-29T13:40:12.009Z","0.2.5":"2026-02-09T09:09:34.989Z","0.2.6":"2026-02-17T17:25:39.724Z"},"bugs":{"url":"https://github.com/dax-side/jwt-abstraction/issues"},"author":{"name":"Damola"},"license":"MIT","homepage":"https://dax-side.github.io/jwt-abstraction-site","keywords":["jwt","jsonwebtoken","authentication","auth","express","middleware","typescript","access-token","refresh-token","zero-config"],"repository":{"type":"git","url":"git+https://github.com/dax-side/jwt-abstraction.git"},"description":"Stop writing the same JWT auth code in every project. Separate secrets for access and refresh tokens.","maintainers":[{"name":"dax-side","email":"damolaadegbite77@gmail.com"}],"readme":"# @dax-side/jwt-abstraction\n\n[![npm version](https://badge.fury.io/js/@dax-side%2Fjwt-abstraction.svg)](https://www.npmjs.com/package/@dax-side/jwt-abstraction)\n[![GitHub](https://img.shields.io/github/stars/dax-side/jwt-abstraction?style=social)](https://github.com/dax-side/jwt-abstraction)\n\nStop writing the same JWT auth code in every project.\n\n## The problem\n\nEvery Node.js project needs JWT auth. Every time you start a new project, you write the same 60 lines:\n- Import jsonwebtoken\n- Configure algorithms and expiry\n- Create separate access/refresh tokens\n- Build Express middleware  \n- Handle token errors\n\nSame code. Different project. Over and over.\n\nThis package does it in 3 lines.\n\n## Features\n\n- Zero-config JWT with secure defaults\n- Automatic access/refresh token pairs\n- Separate secrets for access and refresh tokens\n- Express middleware included\n- TypeScript support with strict mode\n- Proper error types\n- 100% test coverage\n- Zero dependencies except jsonwebtoken\n\n## Install\n\n```bash\nnpm install @dax-side/jwt-abstraction\n```\n\n## Use it\n\n```typescript\nimport { useJwt } from '@dax-side/jwt-abstraction';\n\nconst jwt = useJwt();\n\nconst tokens = jwt.create({ userId: 123, email: 'user@example.com' });\nconst payload = await jwt.verify(tokens.accessToken);\n\napp.get('/profile', jwt.protect(), (req, res) => {\n  res.json({ user: req.user });\n});\n```\n\nThree lines. Done.\n\n## Quick start\n\n1. `npm install @dax-side/jwt-abstraction`\n2. Set `JWT_SECRET=your-secret` in your environment\n3. Add the code above to your Express app\n\nYou now have working JWT auth.\n\n## How it works\n\nSet a secret in your environment:\n\n```bash\nJWT_SECRET=your-secret-here\n```\n\nOr pass it directly:\n\n```typescript\nconst jwt = useJwt({ secret: 'your-secret' });\n```\n\nThe package creates two tokens: an access token (15 minutes) and a refresh token (7 days). Both use HS256 signing by default.\n\n## Better security: separate secrets\n\nUse different secrets for access and refresh tokens:\n\n```typescript\nJWT_SECRET=your-access-secret\nJWT_REFRESH_SECRET=your-refresh-secret\n```\n\nWhy? Refresh tokens live longer. If your access secret leaks, refresh tokens stay safe.\n\nGenerate strong secrets:\n\n```bash\nnode -e \"console.log(require('crypto').randomBytes(64).toString('hex'))\"\n```\n\n## Use your own environment variable names\n\n```typescript\nconst jwt = useJwt({\n  secret: process.env.AUTH_KEY,\n  refreshTokenSecret: process.env.REFRESH_KEY,\n});\n```\n\n`JWT_SECRET` is a convention, not a requirement. Name your variables whatever you want.\n\n## Complete example\n\n```typescript\nimport express from 'express';\nimport { useJwt, TokenExpiredError, InvalidTokenError } from '@dax-side/jwt-abstraction';\n\nconst app = express();\nconst jwt = useJwt();\n\napp.use(express.json());\n\napp.post('/login', (req, res) => {\n  const user = { userId: 123, email: 'user@example.com' };\n  const tokens = jwt.create(user);\n  res.json(tokens);\n});\n\napp.get('/profile', jwt.protect(), (req, res) => {\n  res.json({ user: req.user });\n});\n\napp.post('/refresh', async (req, res) => {\n  try {\n    const { refreshToken } = req.body;\n    const newTokens = await jwt.refresh(refreshToken);\n    res.json(newTokens);\n  } catch (error) {\n    res.status(401).json({ error: 'Invalid refresh token' });\n  }\n});\n\napp.post('/logout', jwt.protect(), async (req, res) => {\n  res.json({ message: 'Logged out' });\n});\n\napp.listen(3000);\n```\n\n## Error handling\n\nCatch specific error types:\n\n```typescript\nimport { TokenExpiredError, InvalidTokenError, NoSecretError } from '@dax-side/jwt-abstraction';\n\ntry {\n  const payload = await jwt.verify(token);\n} catch (error) {\n  if (error instanceof TokenExpiredError) {\n    // Token expired\n  } else if (error instanceof InvalidTokenError) {\n    // Token malformed or tampered with\n  } else if (error instanceof NoSecretError) {\n    // Secret not configured\n  }\n}\n```\n\n## Configuration options\n\n```typescript\nconst jwt = useJwt({\n  secret: 'your-secret',\n  refreshTokenSecret: 'refresh-secret',\n  accessTokenTTL: '30m',\n  refreshTokenTTL: '14d',\n  algorithm: 'HS512',\n  issuer: 'myapp.com',\n  audience: 'api-users',\n});\n```\n\n## Common issues\n\n**Error: JWT_SECRET environment variable is not set**\n\nSet `JWT_SECRET` in your environment or pass the `secret` option.\n\n**Error: Token expired**\n\nAccess tokens expire in 15 minutes by default. Use the refresh token to get new ones.\n\n**Middleware not attaching req.user**\n\nMake sure `express.json()` runs before `jwt.protect()`.\n\n## Issuer and audience\n\nFor a single backend API, `issuer` and `audience` add complexity without real security benefit. Your secret is the security.\n\nThese matter for:\n- Multiple microservices sharing secrets\n- OAuth/OpenID flows\n- Tokens crossing organizational boundaries\n\nFor a standard web app, you can ignore them.\n\n## What this package doesn't do\n\n**Token storage**: Storing tokens (Redis, database) is your job. This package creates and verifies them.\n\n**Token blacklisting**: When you refresh a token, the old one stays valid until expiry. If you want to invalidate tokens, build your own blacklist.\n\n**Social login**: Use Passport or similar. This handles JWT operations only.\n\n**Password hashing**: Use bcrypt. Different concern.\n\n**Framework support**: Works with Express. Other frameworks might come later.\n\n## Token invalidation example\n\nUsing Redis to track used refresh tokens:\n\n```typescript\napp.post('/refresh', async (req, res) => {\n  const { refreshToken } = req.body;\n  \n  if (await redis.exists(`used:${refreshToken}`)) {\n    return res.status(401).json({ error: 'Token already used' });\n  }\n  \n  const newTokens = await jwt.refresh(refreshToken);\n  await redis.setex(`used:${refreshToken}`, 604800, '1');\n  \n  res.json(newTokens);\n});\n```\n\n## Standalone functions\n\nDon't want the factory pattern? Import functions directly:\n\n```typescript\nimport { createTokens, verifyToken, protect } from '@dax-side/jwt-abstraction';\n\nconst tokens = createTokens({ userId: 1 }, { secret: 'my-secret' });\nconst payload = await verifyToken(token, { secret: 'my-secret' });\napp.get('/protected', protect({ secret: 'my-secret' }), handler);\n```\n\n## Why not use...\n\n**jsonwebtoken directly?**\n\nYou can. This removes the boilerplate. If you want full control, use jsonwebtoken. If you want it done in 3 lines, use this.\n\n**Passport?**\n\nDifferent use case. Passport handles multiple auth strategies (OAuth, local, SAML). This is JWT-only and simpler.\n\n**express-jwt?**\n\nDeprecated and archived. Doesn't handle token creation or refresh flows.\n\n## Contributing\n\nFound a bug? Have a feature request?\n- [Open an issue](https://github.com/dax-side/jwt-abstraction/issues)\n- [Submit a PR](https://github.com/dax-side/jwt-abstraction/pulls)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}