{"_id":"@0-auth/zero-auth","_rev":"9-d7b9393244d4e4c9a7b5765c2cd75449","name":"@0-auth/zero-auth","dist-tags":{"latest":"1.4.1"},"versions":{"1.0.0":{"name":"@0-auth/zero-auth","version":"1.0.0","keywords":["jwt","authentication","authorization","middleware","express","typescript","refresh-token","cookie","rbac"],"author":"","license":"MIT","_id":"@0-auth/zero-auth@1.0.0","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://github.com/0-auth/zero-auth#readme","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"7b9c0d7ce0296e5234508eeb06c63989e490b59f","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.0.0.tgz","fileCount":9,"integrity":"sha512-Hr5xsCoaf0IRDLbebe91roNQ85u0aMxxTlRiA5pnipuIIfBIR9z+GAFmKN4dDr5ysUiU9A9xXQB2mtOJW8ivgA==","signatures":[{"sig":"MEQCIEAy2f5WnvfRci3WcpK9NwkfirUCT5vPtn4ckZgSwWTKAiASU32f/yeO74o+fkg/CAEuK4TkjQOKRJ9xCSEh8eMt6A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":254577},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"8507c041d049f0f9561ca46fb9c7283b67ff37d8","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"node node_modules/typedoc/bin/typedoc","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","test:watch":"node node_modules/vitest/vitest.mjs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight, developer-first JWT authentication package for Node.js applications","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.0.0_1787240235057_0.6101844346268721","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@0-auth/zero-auth","version":"1.0.1","keywords":["jwt","authentication","authorization","middleware","express","typescript","refresh-token","cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.0.1","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://github.com/0-auth/zero-auth#readme","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"ac214c2fbffa7e38f6b54c244392a379239ce144","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.0.1.tgz","fileCount":9,"integrity":"sha512-6BR/0jiizCzgkgLqwQDzZggCO8dXzbU87x/7T5ZRElDC20qg/Hfc1gnXEa9QRPFFY6x74+kAIO2ibqZeweF4yw==","signatures":[{"sig":"MEYCIQCl+9RBVq8Wjk1AhGuUCuMDXAHzpY+RzxocoWvaVMnZqgIhAO/9cKSehakw7McSKfIbPxFWP0jJk9jPpKgfBgrkuJuY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":252583},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"630d816ef4e75a4bcb9c21756d935470b2348178","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"node node_modules/typedoc/bin/typedoc","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","test:watch":"node node_modules/vitest/vitest.mjs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight, developer-first authentication layer for Node.js APIs — JWT, refresh-token rotation, HTTP-only cookies, and RBAC without an external auth platform","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.0.1_1787245542823_0.9135374490246695","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@0-auth/zero-auth","version":"1.0.2","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.0.2","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"0fdd5180934d004ce0c12d0462cc4ee85ea4c41c","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.0.2.tgz","fileCount":9,"integrity":"sha512-QY0r6vWBiDFkKrGh9F+fGqiUlSzyUc4gzcE8J55gm/M0iGy/Wb26oluFArA44z6LTOmttrkwhO2oYvfN1k2Uwg==","signatures":[{"sig":"MEQCIGtmOH60C3IonOCJDofK0w2tm/xh0QsdNBTiXbS7prGuAiAtTWWNGzZX/7Megdv3hUqSLFjfgfI8JR1Qh9ztXV6IVA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":259421},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"77eb9fded6b200f8c8efc813aa46d05869ea16d2","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"npm run docs:build","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","docs:api":"node node_modules/typedoc/bin/typedoc","docs:dev":"vitepress dev docs","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","docs:build":"npm run docs:api && vitepress build docs","test:watch":"node node_modules/vitest/vitest.mjs","docs:preview":"vitepress preview docs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build","docs:build:versioned":"npm run docs:api && vitepress build docs --outDir docs/.vitepress/dist/v1"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","vitepress":"^1.6.4","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","typedoc-plugin-markdown":"^4.12.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.0.2_1787335855472_0.655451856400439","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@0-auth/zero-auth","version":"1.1.2","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.1.2","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"5e97bf1a63e5dcae9f58476b19513f629b81b427","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.1.2.tgz","fileCount":10,"integrity":"sha512-4ScBeFKcFtTD3FjK0fSdf6WZJobfFEEg6rJy97x6L9DV6XG23HGhxKurN/CLi6OVf7Pv5fVvDvcUVUcw/Xb8vQ==","signatures":[{"sig":"MEYCIQCma9H7OIecPAQY7vS/EEtoNkNn99ue5BcN+o6WvvImSwIhAJ28sgdlspGIIX4wxtwTui1S9iYnOEn/lRaR5b8OBYhi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":270930},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"2f6c1d5dfa572f893b89205c6c26ced71e79e25d","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"npm run docs:build","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","docs:api":"node node_modules/typedoc/bin/typedoc","docs:dev":"vitepress dev docs","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","docs:build":"npm run docs:api && vitepress build docs","test:watch":"node node_modules/vitest/vitest.mjs","docs:preview":"vitepress preview docs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build","docs:build:versioned":"npm run docs:api && vitepress build docs --outDir docs/.vitepress/dist/v1"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","vitepress":"^1.6.4","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","typedoc-plugin-markdown":"^4.12.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.1.2_1787585929928_0.13592726796389631","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@0-auth/zero-auth","version":"1.1.3","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.1.3","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"620ed137dbd0a730505910d6043e1b3163e1e5eb","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.1.3.tgz","fileCount":10,"integrity":"sha512-HZoGoRygn3HSHRErCCNkTcTZc1zZCYVL1NGHm2wO0ylWkTPpTGVt05bZUMAM4HGXJR6Bz/AbDBgwU2wtCXt30g==","signatures":[{"sig":"MEUCIQDoor9sQ6VPDjevgQYoVWup/Gma2Ht1VcSSQxA8QWTkeQIgDNoEK7XZ0iZS5zUgYIW4vW8C+RzQkMmOhSF80YCIFhs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":271517},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"fdcc07fa1dea2b94ac7c4cb68afe3badf9370fc0","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"npm run docs:build","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","docs:api":"node node_modules/typedoc/bin/typedoc","docs:dev":"vitepress dev docs","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","docs:build":"npm run docs:api && vitepress build docs","test:watch":"node node_modules/vitest/vitest.mjs","docs:preview":"vitepress preview docs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build","docs:build:versioned":"npm run docs:api && vitepress build docs --outDir docs/.vitepress/dist/v1"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","vitepress":"^1.6.4","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","typedoc-plugin-markdown":"^4.12.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.1.3_1787681851494_0.6873164289503026","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@0-auth/zero-auth","version":"1.2.0","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.2.0","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"36cb00f06fbff6eb3d16219c4817a21560ede389","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.2.0.tgz","fileCount":10,"integrity":"sha512-/ZqXzNOtM2ZPmbL82m7o4AD1TjFMbt7NxAuyxkilmjnv9TP28p8GX3jCVRZBC4M7cgg3EbsgambHnNyDe/9vqw==","signatures":[{"sig":"MEQCIDnxFdu/KIs1XupxcCrdcLo4VTiGQQ+F1Jal4Q36KZgjAiAjyZ185yF3xYN5Ye/9u6Hn0Ls/y7Tgyi/fdLzzS/RV2g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":312069},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"1f31d7e47592f3c5f7ade8b377936af34e73ca02","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"npm run docs:build","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","docs:api":"node node_modules/typedoc/bin/typedoc","docs:dev":"vitepress dev docs","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","docs:build":"npm run docs:api && vitepress build docs","test:watch":"node node_modules/vitest/vitest.mjs","docs:preview":"vitepress preview docs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build","docs:build:versioned":"npm run docs:api && vitepress build docs --outDir docs/.vitepress/dist/v1"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","vitepress":"^1.6.4","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","typedoc-plugin-markdown":"^4.12.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.2.0_1788011611426_0.38680143835404035","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@0-auth/zero-auth","version":"1.3.0","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.3.0","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"7ad0bf01f6cb371a73c6c404022a3a580de69c5b","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.3.0.tgz","fileCount":10,"integrity":"sha512-IN8JLhNp2TsbuVWI14JvWex3CttkWNzxvRi3Go4a86MQ9GzX7BkjESeeyfIXtuIBLeYMwrujjmOqHZNLJlsF/A==","signatures":[{"sig":"MEYCIQD8kjvxB8E7gr3VsSpVu7z0m8EdHxZ5byGdmaWXHrLoQAIhAJwYbHJ3Mc7rzHTRJC9g26f0aXcg10yOVy9mgXR8n7J8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":336678},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"31d13f5d8248800634bcc5fe0b7ddda4b205ea39","scripts":{"dev":"node node_modules/tsup/dist/cli-default.js --watch","docs":"npm run docs:build","lint":"node node_modules/eslint/bin/eslint.js src tests","test":"node node_modules/vitest/vitest.mjs run","build":"node node_modules/tsup/dist/cli-default.js","format":"node node_modules/prettier/bin/prettier.cjs --write \"src/**/*.ts\" \"tests/**/*.ts\"","docs:api":"node node_modules/typedoc/bin/typedoc","docs:dev":"vitepress dev docs","lint:fix":"node node_modules/eslint/bin/eslint.js src tests --fix","typecheck":"node node_modules/typescript/bin/tsc --noEmit","docs:build":"npm run docs:api && vitepress build docs","test:watch":"node node_modules/vitest/vitest.mjs","docs:preview":"vitepress preview docs","format:check":"node node_modules/prettier/bin/prettier.cjs --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"node node_modules/vitest/vitest.mjs run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build","docs:build:versioned":"npm run docs:api && vitepress build docs --outDir docs/.vitepress/dist/v1"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","typedoc":"^0.28.19","prettier":"^3.3.3","supertest":"^7.0.0","vitepress":"^1.6.4","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","typedoc-plugin-markdown":"^4.12.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.3.0_1788439953085_0.2753192720846409","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@0-auth/zero-auth","version":"1.4.0","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"author":{"name":"Darshan Kinge"},"license":"MIT","_id":"@0-auth/zero-auth@1.4.0","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"homepage":"https://zero-auth.netlify.app/","bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"dist":{"shasum":"e2dba7db7aa48adb35e8f5aabcc0d22be57ee7fd","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.4.0.tgz","fileCount":10,"integrity":"sha512-xwTILH0ai+Krjhy59X1ICF215zWd0Kp3irrG/d6tFHtw64kBDOsohkGRticOWpi2gP/mOnXWv1u+epm0YXYMbw==","signatures":[{"sig":"MEUCIE372UGLlbKVfrWi9fM9noouWpa6Bc0UO8jsdpHPpO1UAiEAoJwYo2wJ7bvrUk+HCKJR5GAxJQU917zTaO9jkNBqWpQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":355637},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"09f36496adecd4bdf1797f854b321317be9ac350","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest run","build":"tsup","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint src tests --fix","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"vitest run --coverage","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"repository":{"url":"git+https://github.com/0-auth/zero-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","directories":{},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_nodeVersion":"20.20.2","dependencies":{"jose":"^5.9.6"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","eslint":"^9.0.0","vitest":"^2.0.0","express":"^4.21.2","prettier":"^3.3.3","supertest":"^7.0.0","typescript":"^5.6.0","@types/node":"^22.0.0","@types/express":"^5.0.0","@types/supertest":"^6.0.2","@vitest/coverage-v8":"^2.0.0","eslint-config-prettier":"^9.1.0","@typescript-eslint/parser":"^8.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zero-auth_1.4.0_1788552495266_0.8940522425600519","host":"s3://npm-registry-packages-npm-production"}},"1.4.1":{"name":"@0-auth/zero-auth","version":"1.4.1","description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","author":{"name":"Darshan Kinge"},"license":"MIT","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"homepage":"https://zero-auth.netlify.app/","repository":{"type":"git","url":"git+https://github.com/0-auth/zero-auth.git"},"bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"eslint src tests","lint:fix":"eslint src tests --fix","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","typecheck":"tsc --noEmit","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build"},"dependencies":{"jose":"^5.9.6"},"peerDependencies":{"express":"^4.18.0 || ^5.0.0"},"peerDependenciesMeta":{"express":{"optional":true}},"devDependencies":{"@types/express":"^5.0.0","@types/node":"^22.0.0","@types/supertest":"^6.0.2","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/coverage-v8":"^2.0.0","eslint":"^9.0.0","eslint-config-prettier":"^9.1.0","express":"^4.21.2","prettier":"^3.3.3","supertest":"^7.0.0","tsup":"^8.3.0","typescript":"^5.6.0","vitest":"^2.0.0"},"engines":{"node":">=18.0.0"},"sideEffects":["./dist/index.js","./dist/index.mjs"],"_id":"@0-auth/zero-auth@1.4.1","gitHead":"94750a86e8b2badb91adcb071e5896d17f44636c","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-6uC91azTFT7uBFNK+rER0fU8xp2Ndmxlzne+KDrUK/0A0z9NXt/8OXsVYc2VpcBkGXvaoBYT7Rt1uV/YCyDKFQ==","shasum":"055b18766c81742f0d22f2d6ce7954cc5e5efbd0","tarball":"https://registry.npmjs.org/@0-auth/zero-auth/-/zero-auth-1.4.1.tgz","fileCount":10,"unpackedSize":362938,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@0-auth%2fzero-auth@1.4.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCIH9kcm+zCc3Z4iaw+gsX8J+9rfJtCE0LU84BBVqG1zgIgUyvrDhIyYjrzIJYVtTTNSNZET9R98sEIa6JDofUHHKk="}]},"_npmUser":{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"},"directories":{},"maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zero-auth_1.4.1_1788555513206_0.8340732990602222"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-20T15:37:14.866Z","modified":"2026-09-04T20:58:33.700Z","1.0.0":"2026-08-20T15:37:15.264Z","1.0.1":"2026-08-20T17:05:42.994Z","1.0.2":"2026-08-21T18:10:55.623Z","1.1.2":"2026-08-24T15:38:50.049Z","1.1.3":"2026-08-25T18:17:31.676Z","1.2.0":"2026-08-29T13:53:31.569Z","1.3.0":"2026-09-03T12:52:33.219Z","1.4.0":"2026-09-04T20:08:15.403Z","1.4.1":"2026-09-04T20:58:33.352Z"},"bugs":{"url":"https://github.com/0-auth/zero-auth/issues"},"author":{"name":"Darshan Kinge"},"license":"MIT","homepage":"https://zero-auth.netlify.app/","keywords":["jwt","jwt-auth","jwt-authentication","access-token","authentication","authorization","api","middleware","express","express-authentication","nodejs","typescript","refresh-token","refresh-token-rotation","token-revocation","cookie","http-only-cookie","rbac"],"repository":{"type":"git","url":"git+https://github.com/0-auth/zero-auth.git"},"description":"Minimal JWT authentication for Node.js and Express APIs with refresh-token rotation, HTTP-only cookies, and RBAC","maintainers":[{"name":"wtfdrshn","email":"itsmedarshan8@gmail.com"}],"readme":"# @0-auth/zero-auth\n\nMinimal JWT authentication for Node.js and Express APIs.\n\nNo database. No hosted auth service. Just access tokens, refresh-token rotation,\nHTTP-only cookies, and RBAC with middleware your team can understand.\n\n## ⚠️ Attention — Breaking Changes & Upgrade Notes\n\n> [!NOTE]\n> Any release with breaking changes will list them in this section before the\n> rest of the README. Legacy `isRevoked` + `revokeRefreshToken` hooks remain\n> supported for compatibility, but emit a warning and are not concurrency-safe.\n> Use the atomic `consumeRefreshToken` hook for rotated refresh tokens,\n> especially in multi-instance deployments. The new `RefreshTokenStore` API is\n> the recommended integration for shared rotation state.\n\n**Start here:** [5-minute quick start](#quick-start-5-minutes) · [runnable examples](#examples) · [API reference](#api-reference)\n\n**Documentation:** [zero-auth.netlify.app](https://zero-auth.netlify.app/) ·\n[guides](https://zero-auth.netlify.app/v1/) ·\n[API reference](https://zero-auth.netlify.app/v1/api/)\n\n[![npm version](https://img.shields.io/npm/v/@0-auth/zero-auth.svg)](https://www.npmjs.com/package/@0-auth/zero-auth)\n[![npm downloads](https://img.shields.io/npm/dm/@0-auth/zero-auth.svg)](https://www.npmjs.com/package/@0-auth/zero-auth)\n[![CI](https://github.com/0-auth/zero-auth/actions/workflows/ci.yml/badge.svg)](https://github.com/0-auth/zero-auth/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)\n[![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)](https://nodejs.org)\n\n> **JWT auth with refresh-token rotation and reuse detection** for teams that\n> want to keep identity and storage in their own application.\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Scope](#scope)\n- [Security model](#security-model)\n- [Installation](#installation)\n- [Quick Start (5 Minutes)](#quick-start-5-minutes)\n- [Examples](#examples)\n- [Configuration Options](#configuration-options)\n  - [Usage Guides](#usage-guides)\n  - [1. Header / Bearer Token Auth](#1-header--bearer-token-auth)\n  - [2. HTTP-Only Cookie Auth](#2-http-only-cookie-auth)\n  - [CSRF Protection for Cookie Auth](#csrf-protection-for-cookie-auth)\n  - [3. Route Protection & RBAC](#3-route-protection--rbac)\n  - [4. Optional Authentication](#4-optional-authentication)\n  - [5. Token Refresh & Rotation](#5-token-refresh--rotation)\n- [Error Handling & Error Codes](#error-handling--error-codes)\n- [TypeScript Support](#typescript-support)\n- [API Reference](#api-reference)\n  - [Instance Methods (`auth.*`)](#instance-methods-auth)\n  - [Standalone Utilities](#standalone-utilities)\n- [Production & Security Best Practices](#production--security-best-practices)\n- [Compatibility](#compatibility)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Features\n\n- **JWT Validation Policy**: Optionally enforce token issuer, audience, clock tolerance, and `nbf` validation.\n- **Pluggable Refresh Stores**: Connect atomic refresh-token consumption and family revocation to Redis or another store.\n- ⚡ **Zero-Boilerplate Setup**: Initialize with `createAuth()` and start securing routes immediately.\n- 🔒 **Secure by Default**: Cryptographically signed tokens (HS256 via [jose](https://github.com/panva/jose)), enforced minimum 32-character secret length.\n- 🍪 **Built-in Cookie Support**: Seamless HTTP-only cookie handling without extra cookie middleware dependencies.\n- 🛡️ **Cookie CSRF Protection**: Signed double-submit middleware for state-changing cookie requests.\n- 🔄 **Automatic Token Refresh & Rotation**: Built-in refresh route handler with optional token family reuse detection.\n- 🛡️ **Role-Based Access Control (RBAC)**: Flexible role-checking middleware (`auth.authorize(['admin', 'editor'])`).\n- 🔑 **Permission-Based Access Control**: Require fine-grained permissions with `auth.authorizePermissions(['users:read'])`.\n- 🧩 **First-Class TypeScript**: Automatic `req.user` typing via declaration merging with support for custom claims.\n- 🛑 **Structured Error Handling**: Standardized `AuthError` class with typed error codes (`AUTH_TOKEN_EXPIRED`, `AUTH_FORBIDDEN`, etc.).\n- 🌐 **Modern & Edge-Ready**: Dual ESM & CommonJS builds, Node 18+, Bun, serverless, and edge runtime compatible.\n\n---\n\n## Scope\n\n`zero-auth` is an authentication layer, not a complete identity platform. It\ndoes not provide a user database, password hashing, OAuth providers, email\nverification, password reset, MFA, or user-management UI. Your application\nowns those decisions and supplies the user identity used in token claims.\n\n---\n\n## Security model\n\n| Concern | Default approach |\n| --- | --- |\n| Access tokens | Short-lived JWTs, typically `15m` |\n| Refresh tokens | Longer-lived tokens, typically `7d` |\n| Rotation | Enable `refreshOptions.rotate` when replay detection matters |\n| Revocation | Your Redis, database, or other application store |\n| Browser storage | HTTP-only cookies when a cookie flow is appropriate |\n\n`zero-auth` does not choose or manage your user database. Read the full\n[security checklist](https://zero-auth.netlify.app/v1/security) before deploying\nto production.\n\n---\n\n## Installation\n\n```bash\nnpm install @0-auth/zero-auth\n# or\nyarn add @0-auth/zero-auth\n# or\npnpm add @0-auth/zero-auth\n```\n\n> **Note:** If using Express middleware, install `express` (peer dependency):\n> ```bash\n> npm install express\n> ```\n\n---\n\n## Quick Start (5 Minutes)\n\nHere is a complete, copy-pasteable Express application using `zero-auth`:\n\nSet `JWT_ACCESS_SECRET` and `JWT_REFRESH_SECRET` to different random values of\nat least 32 characters before starting the app.\n\n```ts\nimport express from \"express\";\nimport { createAuth } from \"@0-auth/zero-auth\";\n\n// 1. Initialize Auth instance\nconst auth = createAuth({\n  accessSecret: process.env.JWT_ACCESS_SECRET!,\n  refreshSecret: process.env.JWT_REFRESH_SECRET!,\n  accessExpiresIn: \"15m\",\n  refreshExpiresIn: \"7d\",\n});\n\nconst app = express();\napp.use(express.json());\n\n// 2. Login Route (generates and sends token pair or cookies)\napp.post(\"/auth/login\", async (req, res, next) => {\n  try {\n    const { email, password } = req.body;\n    // ... validate credentials against your database ...\n    const userPayload = { id: \"user-123\", email, role: \"admin\" };\n\n    // Option A: Set HTTP-Only cookies + return tokens\n    const tokens = await auth.sendAuthTokens(res, userPayload);\n    res.json({ message: \"Logged in successfully\", tokens });\n\n    // Option B (Bearer only): const tokens = await auth.generateTokenPair(userPayload); res.json(tokens);\n  } catch (err) {\n    next(err);\n  }\n});\n\n// 3. Protected Route (requires valid access token)\napp.get(\"/api/profile\", auth.protect(), (req, res) => {\n  // req.user is automatically typed as AuthUser!\n  res.json({ user: req.user });\n});\n\n// 4. Role-Restricted Route (Admin only)\napp.get(\"/api/admin/dashboard\", auth.protect(), auth.authorize([\"admin\"]), (req, res) => {\n  res.json({ message: `Welcome Admin ${req.user?.id}` });\n});\n\n// 5. Refresh Token Route\napp.post(\"/auth/refresh\", auth.refreshHandler());\n\n// 6. Logout Route (clears HTTP-Only cookies)\napp.post(\"/auth/logout\", (req, res) => {\n  auth.clearAuth(res);\n  res.json({ message: \"Logged out successfully\" });\n});\n\n// 7. Error handling middleware (must be registered after routes)\napp.use(auth.errorHandler);\n\napp.listen(3000, () => console.log(\"Server running on http://localhost:3000\"));\n```\n\n---\n\n## Examples\n\nTwo complete, runnable example projects are included in the\n[`examples/`](https://github.com/0-auth/zero-auth/tree/master/examples) directory:\n\n| Example | Description | Features |\n| ------- | ----------- | -------- |\n| [`express-rest-api`](https://github.com/0-auth/zero-auth/tree/master/examples/express-rest-api) | Stateless Bearer token API for mobile / CLI / SPA clients | `generateTokenPair`, `protect`, `authorize`, `optional`, `refreshHandler`, `decodeToken` |\n| [`express-cookies-redis`](https://github.com/0-auth/zero-auth/tree/master/examples/express-cookies-redis) | Cookie-based auth with Redis-backed refresh token rotation | `sendAuthTokens`, `clearAuth`, CSRF, rotation hooks, family revocation, `onRefreshReuse` |\n\nEach example includes a README with setup instructions and cURL commands for every endpoint.\n\nFor the complete documentation map, read the\n[documentation site](https://zero-auth.netlify.app/v1/). It covers bearer and\ncookie clients, CSRF, roles and permissions, refresh rotation, errors,\ndeployment, testing, versioning, and releases.\n\n```bash\n# Quick start (REST API example)\ncd examples/express-rest-api\nnpm install\nnpm start\n```\n\n---\n\n## Configuration Options\n\nPass your settings to `createAuth(config)`:\n\n```ts\nconst auth = createAuth({\n  // Required\n  accessSecret: process.env.JWT_ACCESS_SECRET!,   // String (min 32 chars)\n  refreshSecret: process.env.JWT_REFRESH_SECRET!, // String (min 32 chars, distinct from accessSecret)\n\n  // Optional JWT validation policy\n  jwt: {\n    issuer: \"https://api.example.com\",\n    audience: \"web-app\",\n    clockTolerance: 5, // Allowed clock skew in seconds\n  },\n\n  // Optional Token Expirations (defaults shown)\n  accessExpiresIn: \"15m\",   // Formats: \"15m\", \"1h\", \"7d\", \"30d\", or milliseconds\n  refreshExpiresIn: \"7d\",\n\n  // Optional Cookie Configuration\n  cookies: {\n    accessTokenName: \"access_token\",   // Cookie name for access token\n    refreshTokenName: \"refresh_token\", // Cookie name for refresh token\n    options: {\n      httpOnly: true,        // Always enforced as true for security\n      secure: true,          // Defaults to true when NODE_ENV === 'production'\n      sameSite: \"lax\",       // 'lax' | 'strict' | 'none'\n      path: \"/\",             // Cookie path\n      domain: undefined,     // Optional cookie domain\n    },\n  },\n\n  // Optional CSRF protection for cookie-authenticated requests\n  csrf: {\n    cookieName: \"csrf_token\",       // Client-readable token cookie\n    headerName: \"x-csrf-token\",     // Header copied from that cookie\n    methods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n  },\n\n  // Optional Refresh Rotation & Revocation\n  refreshOptions: {\n    rotate: false,           // Set to true to enable Refresh Token Rotation\n    // Required when rotate: true: implement an atomic single-use check.\n    // consumeRefreshToken: (oldJti, ctx) => redis.set(..., { NX: true }).then(result => result === \"OK\"),\n    registerRefreshToken: async (newJti, ctx) => {},\n    onRefreshReuse: async (ctx) => {},\n  },\n});\n```\n\nWhen configured, `jwt.issuer` and `jwt.audience` are included in new tokens and\nmust match during verification. `clockTolerance` allows limited clock skew in\nseconds. JWT `nbf` claims are also validated automatically.\n\n---\n\n## Usage Guides\n\n### 1. Header / Bearer Token Auth\n\nFor mobile apps, CLI tools, or traditional REST APIs sending tokens via headers:\n\n```ts\n// Login: Return raw tokens in JSON response\napp.post(\"/auth/login\", async (req, res) => {\n  const tokens = await auth.generateTokenPair({\n    id: \"user_123\",\n    email: \"user@example.com\",\n    role: \"user\",\n  });\n\n  res.json(tokens);\n  // { accessToken: \"eyJ...\", refreshToken: \"eyJ...\" }\n});\n\n// Client sends: Authorization: Bearer <accessToken>\napp.get(\"/api/data\", auth.protect(), (req, res) => {\n  res.json({ data: \"Protected content\", userId: req.user.id });\n});\n```\n\n---\n\n### 2. HTTP-Only Cookie Auth\n\nFor web applications (SPAs, React, Next.js, Vue) to protect against XSS token theft:\n\n```ts\n// Login: Sets secure HTTP-Only cookies on the response automatically\napp.post(\"/auth/login\", async (req, res) => {\n  const user = { id: \"user_123\", role: \"member\" };\n  const tokens = await auth.sendAuthTokens(res, user);\n  res.json({ user, tokens });\n});\n\n// Protected routes automatically read tokens from either Cookie or Authorization header\napp.get(\"/api/data\", auth.protect(), (req, res) => {\n  res.json({ user: req.user });\n});\n\n// Logout: Clears both cookies using the exact same path and options\napp.post(\"/auth/logout\", (req, res) => {\n  auth.clearAuth(res);\n  res.json({ message: \"Logged out\" });\n});\n```\n\n### CSRF Protection for Cookie Auth\n\nCookie-authenticated state-changing requests should include a CSRF token. Add\nthe middleware before your routes and expose a small same-origin endpoint that\nsets and returns the client-readable token:\n\n```ts\napp.use(auth.csrf());\n\napp.get(\"/auth/csrf-token\", (req, res) => {\n  res.json({ csrfToken: auth.csrfToken(res) });\n});\n\napp.post(\"/api/profile\", auth.protect(), (req, res) => {\n  res.json({ updated: true, user: req.user });\n});\n```\n\nThe browser sends the token in the configured header on `POST`, `PUT`, `PATCH`,\nand `DELETE` requests:\n\n```ts\nconst { csrfToken } = await fetch(\"/auth/csrf-token\", {\n  credentials: \"include\",\n}).then((response) => response.json());\n\nawait fetch(\"/api/profile\", {\n  method: \"POST\",\n  credentials: \"include\",\n  headers: { \"x-csrf-token\": csrfToken },\n});\n```\n\nRequests without auth cookies and safe methods such as `GET` pass through. The\nmiddleware does not protect bearer-token requests because browsers do not send\ntheir `Authorization` header automatically. Mount `app.use(auth.csrf())`\nbefore state-changing routes, and keep `app.use(auth.errorHandler)` last.\n\n---\n\n### 3. Route Protection & RBAC\n\nProtect routes and limit access by user roles:\n\n```ts\n// Single role requirement\napp.get(\"/admin\", auth.protect(), auth.authorize([\"admin\"]), adminHandler);\n\n// Multiple allowed roles (user must have at least one)\napp.get(\n  \"/reports\",\n  auth.protect(),\n  auth.authorize([\"admin\", \"manager\", \"auditor\"]),\n  reportsHandler\n);\n```\n\n> **Note:** `auth.authorize()` checks `req.user.role`. Always place `auth.protect()` before `auth.authorize()` in the middleware chain.\n\nFor fine-grained access checks, require every permission listed in the user's\n`permissions` claim:\n\n```ts\napp.get(\n  \"/users\",\n  auth.protect(),\n  auth.authorizePermissions([\"users:read\"]),\n  listUsersHandler\n);\n```\n\n`auth.authorizePermissions()` also requires `auth.protect()` first and returns\n`AUTH_FORBIDDEN` when any required permission is missing.\n\n---\n\n### 4. Optional Authentication\n\nUse `auth.optional()` for endpoints that serve both guests and authenticated users (e.g. public articles with personalized like buttons):\n\n```ts\napp.get(\"/articles/:slug\", auth.optional(), (req, res) => {\n  if (req.user) {\n    // Authenticated user\n    res.json({ article: getArticle(), bookmarked: true });\n  } else {\n    // Guest visitor (req.user is undefined)\n    res.json({ article: getArticle(), bookmarked: false });\n  }\n});\n```\n\n---\n\n### 5. Token Refresh & Rotation\n\n`zero-auth` includes a ready-to-use Express handler for refreshing tokens:\n\n```ts\napp.post(\"/auth/refresh\", auth.refreshHandler());\n```\n\n**How the refresh token is extracted:**\n1. Refresh token cookie (`cookies.refreshTokenName`)\n2. JSON body field (`refreshToken` or `refresh_token`)\n3. `Authorization: Bearer <refreshToken>` header\n\n#### Advanced: Refresh Token Rotation (with Redis)\n\nWhen `refreshOptions.rotate: true` is enabled, a new refresh token is issued on every refresh request, and old tokens are invalidated. If an old token is reused (indicating a stolen token), `onRefreshReuse` is triggered to invalidate the entire token family.\n\n`consumeRefreshToken` should atomically mark the incoming `jti` as consumed and\nreturn `false` when it was already consumed. Use a Redis `SET NX` or equivalent\ndatabase conditional write when the application runs on multiple instances.\nYou can pass a public `refreshStore` instead; its atomic `consume()` method and\noptional `register()` / `revokeFamily()` methods are wired into rotation\nautomatically. Explicit refresh hooks still take precedence.\nThe legacy `isRevoked` + `revokeRefreshToken` pair remains supported for\ncompatibility, but logs a warning and is not concurrency-safe.\n\nInstall `ioredis` in your application, then use the built-in adapter. The\npackage does not add a Redis client dependency to your application:\n\n```bash\nnpm install @0-auth/zero-auth ioredis\n```\n\n```ts\nimport Redis from \"ioredis\";\nimport {\n  createAuth,\n  createRedisRevocationStore,\n} from \"@0-auth/zero-auth\";\n\nconst redis = new Redis(process.env.REDIS_URL);\nconst refreshStore = createRedisRevocationStore(redis);\n\nconst auth = createAuth({\n  accessSecret: process.env.JWT_ACCESS_SECRET!,\n  refreshSecret: process.env.JWT_REFRESH_SECRET!,\n  refreshStore,\n  refreshOptions: {\n    rotate: true,\n    onRefreshReuse: async ({ familyId }) => {\n      if (familyId) await refreshStore.revokeFamily(familyId);\n    },\n  },\n});\n```\n\nThe adapter uses Redis `SET NX` for atomic single-use consumption and tracks\nrefresh-token families with TTLs. It accepts the ioredis-compatible client\nsurface without importing or bundling a Redis client. When a family is\ncompromised, it writes a marker before scanning known members and atomically\nrejects late replacement registrations, so a concurrent replay cannot leave a\nnew usable refresh token behind.\n\n---\n\n## Error Handling & Error Codes\n\nAll errors thrown by `zero-auth` are instances of `AuthError`.\n\n### Built-in Error Handler Middleware\n\n```ts\n// Mount after all routes\napp.use(auth.errorHandler);\n```\n\nDefault JSON error response format:\n```json\n{\n  \"error\": {\n    \"code\": \"AUTH_TOKEN_EXPIRED\",\n    \"message\": \"Token has expired\",\n    \"statusCode\": 401\n  }\n}\n```\n\n### Manual Error Handling\n\n```ts\nimport { isAuthError, AuthError, AUTH_ERROR_CODES } from \"@0-auth/zero-auth\";\n\ntry {\n  const payload = await auth.verifyToken(tokenString);\n} catch (err) {\n  if (isAuthError(err)) {\n    console.error(`Auth failed [${err.code}]: ${err.message} (HTTP ${err.statusCode})`);\n  }\n}\n```\n\n### Standard Error Codes\n\n| Code | Status Code | Description |\n|---|:---:|---|\n| `AUTH_TOKEN_MISSING` | `401` | No authentication token found in request headers or cookies. |\n| `AUTH_TOKEN_INVALID` | `401` | Token is malformed or signature verification failed. |\n| `AUTH_TOKEN_EXPIRED` | `401` | Token has exceeded its expiration time. |\n| `AUTH_UNAUTHORIZED` | `401` | General unauthenticated error (e.g. invalid credentials or missing user state). |\n| `AUTH_FORBIDDEN` | `403` | User is authenticated but does not possess the required role or permission. |\n| `AUTH_CSRF_INVALID` | `403` | Auth cookies are present but the CSRF token is missing or invalid. |\n\n---\n\n## TypeScript Support\n\n`zero-auth` automatically augments Express's `Request` type with `req.user`.\n\n```ts\nimport type { AuthUser } from \"@0-auth/zero-auth\";\n\ninterface AuthUser {\n  id: string;\n  email?: string;\n  role?: string;\n  permissions?: string[];\n  iat?: number;\n  exp?: number;\n  jti?: string;\n  fid?: string; // Token family ID (when rotation is enabled)\n  [key: string]: unknown; // Custom claims\n}\n```\n\nCustom claims in your JWT payload are preserved across token refreshes and are typed on `req.user`:\n\n```ts\n// Sign with custom claims\nawait auth.generateAccessToken({\n  id: \"user_123\",\n  role: \"admin\",\n  tenantId: \"tenant_abc\",\n});\n\n// In route handler\napp.get(\"/tenant\", auth.protect(), (req, res) => {\n  const tenantId = req.user.tenantId; // accessible\n  res.json({ tenantId });\n});\n```\n\n---\n\n## API Reference\n\n### Instance Methods (`auth.*`)\n\nCreated via `const auth = createAuth(config)`:\n\n| Method | Return Type | Description |\n|---|---|---|\n| `generateAccessToken(payload)` | `Promise<string>` | Generates a signed access token. |\n| `generateRefreshToken(payload)` | `Promise<string>` | Generates a signed refresh token. |\n| `generateTokenPair(payload)` | `Promise<{ accessToken, refreshToken }>` | Generates both access and refresh tokens in parallel. |\n| `verifyToken(token)` | `Promise<AuthUser>` | Verifies access token signature and expiration. |\n| `verifyRefreshToken(token)` | `Promise<AuthUser>` | Verifies refresh token signature and expiration. |\n| `decodeToken(token)` | `AuthUser` | Decodes a token **without** verifying signature. |\n| `protect()` | `RequestHandler` | Express middleware: rejects requests without valid access token (401). |\n| `authorize(roles)` | `RequestHandler` | Express middleware: ensures `req.user.role` is in allowed roles (403). |\n| `authorizePermissions(permissions)` | `RequestHandler` | Express middleware: requires every listed permission in `req.user.permissions` (403). |\n| `optional()` | `RequestHandler` | Express middleware: sets `req.user` if valid token present, allows guests. |\n| `csrf()` | `RequestHandler` | Express middleware: validates CSRF tokens on configured methods when auth cookies are present. |\n| `sendAuthTokens(res, payload)` | `Promise<TokenPair>` | Sets access + refresh HTTP-only cookies on `res` and returns tokens. |\n| `clearAuth(res)` | `void` | Clears access and refresh auth cookies from `res`. |\n| `csrfToken(res)` | `string` | Sets and returns a client-readable signed CSRF token. |\n| `refreshHandler()` | `RequestHandler` | Express route handler for refreshing access tokens. |\n| `rotateTokens(payload)` | `Promise<TokenPair>` | Generates a new access + refresh pair (for custom rotation logic). |\n| `errorHandler` | `ErrorRequestHandler` | Express error middleware for handling `AuthError` responses. |\n\n---\n\n### Standalone Utilities\n\nAll core helpers are also exported directly for custom architectures:\n\n```ts\nimport {\n  // Token Helpers\n  signToken,\n  verifyToken,\n  decodeToken,\n\n  // Extractors\n  extractToken,\n  extractRefreshToken,\n\n  // Cookie Utilities\n  setCookie,\n  clearCookie,\n  parseCookieHeader,\n\n  // Error Helpers\n  AuthError,\n  isAuthError,\n  authErrorHandler,\n\n  // In-Memory Revocation (Testing / Dev)\n  createInMemoryRevocationStore,\n  // Redis-backed revocation (distributed deployments)\n  createRedisRevocationStore,\n} from \"@0-auth/zero-auth\";\n```\n\n| Utility | Description |\n|---|---|\n| `signToken(payload, secret, options)` | Low-level JWT signing function using `jose`. |\n| `verifyToken(token, secret)` | Low-level JWT verification function. |\n| `decodeToken(token)` | Unsafely decodes token payload without signature verification. |\n| `extractToken(req, cookieName?)` | Extracts access token from `Authorization` header or cookie. |\n| `extractRefreshToken(req, cookieName?)` | Extracts refresh token from cookie, body, or header. |\n| `setCookie(res, name, value, options)` | Sets an HTTP-only cookie with secure defaults. |\n| `clearCookie(res, name, options)` | Clears a cookie matching its path/domain/sameSite settings. |\n| `parseCookieHeader(cookieHeader)` | Zero-dependency cookie string parser. |\n| `createInMemoryRevocationStore()` | In-memory token revocation helper for development and tests. |\n| `createRedisRevocationStore(redis, ttlSeconds?)` | ioredis-compatible store for atomic rotation and family revocation. |\n\n---\n\n## Production & Security Best Practices\n\n1. **Secret Keys**:\n   - Always supply separate `accessSecret` and `refreshSecret` values with a minimum length of 32 characters.\n   - Generate secure keys using:\n     ```bash\n     node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n     ```\n2. **HTTPS & Cookies**:\n   - In production (`NODE_ENV=production`), `secure: true` is automatically enabled on cookies so tokens are only transmitted over HTTPS.\n   - HTTP-only cookies prevent client-side JavaScript access, neutralizing XSS token theft.\n   - Mount `auth.csrf()` for cookie-authenticated state-changing requests and send the token in the configured header.\n3. **Token Lifespans**:\n   - Keep `accessExpiresIn` short (`15m` recommended).\n   - Refresh tokens can have longer lifespans (`7d` - `30d`).\n4. **Token Revocation in Distributed Systems**:\n   - Use Redis or your primary database with TTLs to track revoked `jti` identifiers when `refreshOptions.rotate: true` is enabled.\n5. **Abuse Prevention**:\n   - Rate-limit login, registration, refresh, and password-reset endpoints.\n   - Use an allow-listed CORS policy for browser clients.\n   - Monitor authentication failures, refresh replays, and revocation-store errors.\n\n---\n\n## Compatibility\n\n| Environment | Supported | Notes |\n|---|:---:|---|\n| **Node.js** | >= 18.0.0 | Full ESM & CommonJS support |\n| **Express** | 4.x & 5.x | Peer dependency for middleware |\n| **Bun** | >= 1.0.0 | Native runtime support |\n| **TypeScript** | >= 5.0.0 | Declarations bundled |\n| **Serverless / Edge** | ✅ | Powered by `jose` (Web Crypto API compliant) |\n\nThe npm tarball includes the README, CHANGELOG, license, compiled ESM/CommonJS\nbuilds, and TypeScript declarations. The full guide and generated API site are\nbuilt from the repository's `docs/` source.\n\n---\n\n## Contributing\n\nFound a bug or have an idea? [Open an issue](https://github.com/0-auth/zero-auth/issues)\nor read the [contribution guide](https://github.com/0-auth/zero-auth/blob/master/CONTRIBUTING.md).\n\n---\n\n## License\n\n[MIT](./LICENSE) © zero-auth contributors\n","readmeFilename":"README.md"}