{"_id":"passport-jose","_rev":"9-6d766016c7007053e6f2d88061c210c8","name":"passport-jose","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"passport-jose","version":"0.1.0","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.1.0","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"2651e38b0e3a4e7480609279e550730a9e37461b","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.1.0.tgz","fileCount":21,"integrity":"sha512-zKcl2jFR1byYfpdGm6VTE3oy994i/bcERKlGvfO/EWFkjxTDCdbGXrltRa//8tofpKMTAlAihmn3jn97sdE9Ag==","signatures":[{"sig":"MEUCID+x5pA6EF4SR1xlrCwWyGh24TxuPnqemSPMgapmRwVPAiEA/wl1PONMmbh/TlKVwAZimr844BDSy4oroLoBUSNH3cc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76206},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","testcov":"nyc npm run test:legacy","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.1.0_1757803081074_0.586655536498796","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"passport-jose","version":"0.1.1","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.1.1","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"e94261ac13964a85cdeae7cb4c22cb01c3dd8bac","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.1.1.tgz","fileCount":23,"integrity":"sha512-iz9IMBHD+w3e1LG2kAZTmEgMfaWkXin+AxFuBpTaqz3nrZeCbnNolwHLTfoPyLpW2SS8e+2RoLfeG4DK/dWh2Q==","signatures":[{"sig":"MEYCIQCxGVdmNa9xp/BTk201nAR1qDhxUnpW1v91vEIHn79PyQIhAI0CQhoKEsHb+zhPgE5KtHSXd6zPVW/lzCfaR9O1rNoB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52867},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.1.1_1757803622657_0.10375889361237545","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"passport-jose","version":"0.1.2","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.1.2","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"45bf12809112f2a035df1949ec8e2bbff3768058","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.1.2.tgz","fileCount":23,"integrity":"sha512-CtmOQLr62wnVPSXDq1Tec7TKvw7QWXcD8fgKBn4jqbTkFAs8bWdRiX0n2z0/Vx7aNKKJhS9t+/xCL0xI8x6iFw==","signatures":[{"sig":"MEYCIQC5QI/UxXbtsgEMUYMNkgi0aghOjjXiC6M7IMQ6rWDpqAIhAIBU6u60GqvGQxuyPXT/2i+g30FFhh/7mp7W9TckSTYM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32372},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.1.2_1757803825844_0.7498037078316149","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"passport-jose","version":"0.1.3","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.1.3","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"e2ea6889d3f5affe3ce78cd85a2ade7c7fbd7187","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.1.3.tgz","fileCount":18,"integrity":"sha512-qh9CVgkIfL2dIQ/Qigu/p8Tscf0iY8EtH+UJSXo6UXiS3GDgXn/vYSEWeGTNlN36pZK2uz829cCrVZr+4QY0LQ==","signatures":[{"sig":"MEQCIFWgGU7CcI6F+06xTQk79J2kQRbbjvxdY7VKwVXBf2xrAiAz8UgcLLhsnG6RwUmCxf7qAIJYqSE3bkGF4F6bFzxn8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26303},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"rm -rf dist && npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.1.3_1757803920138_0.49334640395835705","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"passport-jose","version":"0.1.4","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.1.4","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"ec80632747a63f1c15e6b8968a4aabdd54eb717b","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.1.4.tgz","fileCount":13,"integrity":"sha512-cExzCge7uQ0OdUlcGN3g9Pol0lQHPQXpAAd1IhvDyVFwrBM83gEwKv0CxDaMPsrkMY0GwWcRXw2aIbxL9/x7OA==","signatures":[{"sig":"MEYCIQCvllJQI0Zz3zc8yfrh1n+hvDJ1DZj+I/JFclj63AD/DAIhANdK77E61ZkCs2lg5WQDig+NJwFaHurSfGxUw7wyEdUe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22836},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"rm -rf dist && npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.1.4_1757804013498_0.6320242408058989","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"passport-jose","version":"0.2.0","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.2.0","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"fabe3cb44a57a46f712d36a30523d10a6b023e35","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.2.0.tgz","fileCount":15,"integrity":"sha512-kFcoCgCdbO+k6xhHL7cIs0C92wdEsuadncHcFLr/YFMuadyIVE0AvPzaWX14SEv70PgR/aq56tkS41cSzTv1NA==","signatures":[{"sig":"MEQCIBl8QkVfJoSQRYRlTiB/dvUGKNt+NEbnK5DVcnlBpjq+AiBP/+7SLyvmXRiUrDEAJEforVpizKwoIa6KhkjBko+dbg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33425},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"rm -rf dist && npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6","jsonwebtoken":"^9.0.2","passport-strategy":"^1"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@types/jsonwebtoken":"^9","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.2.0_1757819711751_0.878747712899399","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"passport-jose","version":"0.3.0","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication","express","nestjs","koa","eddsa","es256","rs256","hs256"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.3.0","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"01927f570e4617a7b298d14436a8317f64bd8034","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.3.0.tgz","fileCount":15,"integrity":"sha512-dF0MZm7m97ztacuhWdwbi7EIRrIuJ1q7YW4ISeUt1x25Vk+du/dNhao1uuY0mb2M5vNL/oqTCvk5htDhh+mVcQ==","signatures":[{"sig":"MEYCIQCTz/MBCKw0FHRHi34wa6pr0UnEgltKmc34FFeYL0NaDgIhAOkLuJPj98xJ8tVnDlDS5auqDH0ymTvx/XkKK4aSQJB6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43248},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"gitHead":"945328c5207d34077d732fa7e87090c11312a0d5","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"rm -rf dist && npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6","passport-strategy":"^1"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.3.0_1757880374147_0.6090658249847283","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"passport-jose","version":"0.3.1","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication","express","nestjs","koa","eddsa","es256","rs256","hs256"],"author":{"name":"asyne"},"license":"MIT","_id":"passport-jose@0.3.1","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"homepage":"https://github.com/asyne/passport-jose","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"dist":{"shasum":"cfee44efc1c54684207a2f68cb73b454df930b41","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.3.1.tgz","fileCount":15,"integrity":"sha512-6Mh5ickFe3UXSSnWqqg12WbAsz8R35TEEBxmxGE4pli/jHUYoIeaMtj4MR39aylEXXrmaDTsrJAAd6y8t4bcTg==","signatures":[{"sig":"MEYCIQCcelY6dkzgPS5iciI81MVz3/3DlJfFS3zyTUxW8s8sAwIhAMAKm8itkmSc3MGG4OrKWbmAxTFNv+Sw0ZiEP1uHCDKM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":45688},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"gitHead":"95151a56c4b645b75ea01d25ee12c5eaf8370c3c","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"rm -rf dist && npm run build"},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"repository":{"url":"git+https://github.com/asyne/passport-jose.git","type":"git"},"_npmVersion":"11.6.0","description":"Passport strategy for authenticating with JWTs using the JOSE library","directories":{},"_nodeVersion":"24.8.0","dependencies":{"jose":"^6","passport-strategy":"^1"},"_hasShrinkwrap":false,"packageManager":"yarn@4.9.4","devDependencies":{"vitest":"^3.2.4","typescript":"^5.9.2","@types/node":"^20.19.14","@vitest/coverage-v8":"^3.2.4","@types/passport-strategy":"^0.2.38"},"_npmOperationalInternal":{"tmp":"tmp/passport-jose_0.3.1_1757884286516_0.6561882511281563","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"passport-jose","version":"0.3.2","description":"Passport JWT strategy with EdDSA, ES256 and modern cryptographic algorithm support via JOSE","author":{"name":"asyne"},"main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","publish:npm":"npm publish --registry https://registry.npmjs.org/","publish:gh":"npm publish --registry https://npm.pkg.github.com","publish":"npm run publish:npm && npm run publish:gh","prepublishOnly":"rm -rf dist && npm run build"},"dependencies":{"jose":"^6.1.0","passport-strategy":"^1.0.0"},"devDependencies":{"@types/node":"^20.19.14","@types/passport-strategy":"^0.2.38","@vitest/coverage-v8":"^3.2.4","typescript":"^5.9.2","vitest":"^3.2.4"},"repository":{"type":"git","url":"git+https://github.com/asyne/passport-jose.git"},"keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication","express","nestjs","koa","eddsa","es256","rs256","hs256"],"license":"MIT","bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"homepage":"https://github.com/asyne/passport-jose","engines":{"node":">=20.0.0"},"packageManager":"yarn@4.9.4","_id":"passport-jose@0.3.2","gitHead":"dede39528f6aa3a4b4c232010438b1f6262a0508","_nodeVersion":"24.8.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-eb7Hxfm1H//n1fyBi1ndIPpkWeqqh6+Y5DL6H/TvcH+domMBfJRyF9IlHhIqW6Gr2cOEoD6lSSQ+d5H0V1SAwQ==","shasum":"1280a0b6f04456d2e8609f7e93d2976fb52951d0","tarball":"https://registry.npmjs.org/passport-jose/-/passport-jose-0.3.2.tgz","fileCount":15,"unpackedSize":45922,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCXOvExfcORmb+S3w9aAto+DLlfAeVlz6bIMUn4TFxODgIgUbdwcUsoqEzOo07I983NvAqH+ScQ3xuFeO7qhAh2k6U="}]},"_npmUser":{"name":"hates","email":"asyne.inout@gmail.com"},"directories":{},"maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/passport-jose_0.3.2_1757886605497_0.12238813571685281"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-13T22:38:01.073Z","modified":"2025-09-14T21:50:05.863Z","0.1.0":"2025-09-13T22:38:01.281Z","0.1.1":"2025-09-13T22:47:02.814Z","0.1.2":"2025-09-13T22:50:26.040Z","0.1.3":"2025-09-13T22:52:00.337Z","0.1.4":"2025-09-13T22:53:33.690Z","0.2.0":"2025-09-14T03:15:11.958Z","0.3.0":"2025-09-14T20:06:14.346Z","0.3.1":"2025-09-14T21:11:26.697Z","0.3.2":"2025-09-14T21:50:05.674Z"},"bugs":{"url":"https://github.com/asyne/passport-jose/issues"},"author":{"name":"asyne"},"license":"MIT","homepage":"https://github.com/asyne/passport-jose","keywords":["jwt","passport","strategy","json","web","token","jose","bearer","authentication","express","nestjs","koa","eddsa","es256","rs256","hs256"],"repository":{"type":"git","url":"git+https://github.com/asyne/passport-jose.git"},"description":"Passport JWT strategy with EdDSA, ES256 and modern cryptographic algorithm support via JOSE","maintainers":[{"name":"hates","email":"asyne.inout@gmail.com"}],"readme":"# passport-jose\n\n[![npm version](https://badge.fury.io/js/passport-jose.svg)](https://www.npmjs.com/package/passport-jose)\n[![Node.js CI](https://github.com/asyne/passport-jose/actions/workflows/ci.yml/badge.svg)](https://github.com/asyne/passport-jose/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/asyne/passport-jose/graph/badge.svg)](https://codecov.io/gh/asyne/passport-jose)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)\n[![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA modern, security-focused [Passport](http://passportjs.org/) strategy for authenticating with [JSON Web Tokens](https://jwt.io) using the [jose](https://github.com/panva/jose) library.\n\n**Motivation**: This library was created to bring support for modern JWT algorithms like **EdDSA** (Ed25519/Ed448), **ES256**, and other contemporary cryptographic standards to Passport JWT middleware. Built from the ground up in TypeScript, it focuses on Bearer token authentication with enhanced security through the modern `jose` library, designed to secure sessionless API endpoints. While the original `passport-jwt` remains excellent for traditional use cases, `passport-jose` leverages cutting-edge algorithms and security features that weren't available in legacy JWT libraries.\n\n## Table of Contents\n\n- [Key Features](#key-features) - What makes passport-jose unique\n- [Installation](#installation) - Add to your project\n- [Quick Start](#quick-start) - Get running in 2 minutes\n- [Basic Usage](#basic-usage) - Essential configuration and setup\n  - [Configure Strategy](#configure-strategy)\n  - [Example Configuration](#example-configuration)\n  - [Using Different Key Formats](#using-different-key-formats)\n  - [JWT Extraction Methods](#jwt-extraction-methods)\n  - [Authenticate Requests](#authenticate-requests)\n  - [Include JWT in Requests](#include-jwt-in-requests)\n- [Framework Integration](#framework-integration) - Use with popular frameworks\n  - [NestJS Integration](#nestjs-integration)\n  - [Express.js Integration](#expressjs-integration)\n  - [GraphQL Integration](#graphql-integration)\n- [Advanced Topics](#advanced-topics) - Production features and customization\n  - [Remote JWKS Integration](#remote-jwks-integration)\n    - [Basic JWKS Usage](#basic-jwks-usage)\n    - [Popular Identity Provider Configurations](#popular-identity-provider-configurations)\n    - [JWKS Configuration Options](#jwks-configuration-options)\n  - [Multi-tenant Support](#multi-tenant-support)\n  - [EdDSA Keys](#eddsa-keys)\n  - [Custom JWT Extractors](#custom-jwt-extractors)\n- [Migration from passport-jwt](#migration-from-passport-jwt) - Upgrade guide\n- [Troubleshooting](#troubleshooting) - Common issues and solutions\n- [API Reference](#api-reference) - Complete API documentation\n- [Security Considerations](#security-considerations) - Production security best practices\n- [Development](#development) - Build and contribute\n- [License](#license)\n- [Credits](#credits)\n\n## Key Features\n\n- **Enhanced Security**: Uses the modern [jose](https://github.com/panva/jose) library (v6+) with support for modern algorithms like **EdDSA**\n- **Bearer Token Focused**: Exclusively supports RFC 6750 Bearer token authentication\n- **Full TypeScript**: Complete TypeScript implementation with strict typing\n- **Modern Standards**: Built for ES2023 with latest JavaScript features\n- **Native Key Support**: Supports CryptoKey, KeyObject, JWK, and Uint8Array formats natively\n- **Performance**: Optimized JWT verification using native crypto APIs and minimal dependencies\n- **Lightweight**: Minimal bundle footprint with only essential dependencies (`jose` + `passport-strategy`)\n- **Multi-tenant Ready**: Dynamic key resolution for enterprise applications\n\n## Installation\n\n```bash\n# npm\n$ npm install passport-jose\n\n# pnpm\n$ pnpm add passport-jose\n\n# yarn\n$ yarn add passport-jose\n```\n\n## Quick Start\n\nGet up and running with `passport-jose` in under 2 minutes:\n\n```typescript\nimport passport from 'passport';\nimport { Strategy, ExtractJwt } from 'passport-jose';\n\n// 1. Configure the strategy\nconst secretKey = new TextEncoder().encode('your-256-bit-secret');\n\npassport.use(new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withSecretOrKey: secretKey,\n  algorithms: ['HS256']\n}, (payload, done) => {\n  // 2. Verify the user\n  const user = { id: payload.sub, email: payload.email };\n  done(null, user);\n}));\n\n// 3. Protect your routes\napp.get('/profile',\n  passport.authenticate('jwt', { session: false }),\n  (req, res) => res.json({ user: req.user })\n);\n```\n\nSend requests with the JWT in the Authorization header:\n```bash\ncurl -H \"Authorization: Bearer YOUR_JWT_TOKEN\" http://localhost:3000/profile\n```\n\n## Basic Usage\n\n### Configure Strategy\n\nThe JWT authentication strategy is constructed as follows:\n\n```typescript\nimport { Strategy, ExtractJwt, type JoseKey } from 'passport-jose';\n\nnew Strategy(options, verify)\n```\n\n`options` is an object containing configuration for token extraction and verification:\n\n* `withSecretOrKey` - JOSE-compatible key for JWT verification (CryptoKey, KeyObject, JWK, or Uint8Array). **REQUIRED** unless `withKeyProvider` is provided.\n* `withKeyProvider` - Dynamic key resolution callback: `(request, rawJwtToken, done) => void` where `done` has signature `(err: Error | string | null, key?: JoseKey) => void`. **REQUIRED** unless `withSecretOrKey` is provided.\n* `jwtFromRequest` - (**REQUIRED**) Function that extracts the JWT from the request: `(req) => string | null`\n* `issuer` - Expected JWT \"iss\" (Issuer) claim value(s). Makes the claim presence required.\n* `audience` - Expected JWT \"aud\" (Audience) claim value(s). Makes the claim presence required.\n* `algorithms` - List of accepted JWS \"alg\" values (e.g., `[\"HS256\", \"RS256\"]`)\n* `subject` - Expected JWT \"sub\" (Subject) claim value. Makes the claim presence required.\n* `maxTokenAge` - Maximum time elapsed from JWT \"iat\" claim (e.g., `\"1h\"`, `3600`)\n* `clockTolerance` - Clock skew tolerance for time-based claims (e.g., `\"30s\"`, `30`)\n* `typ` - Expected JWT \"typ\" (Type) header parameter value\n* `passReqToCallback` - If `true`, request is passed to verify callback as first argument\n\n`verify` is a function with the parameters `verify(jwt_payload, done)` or `verify(req, jwt_payload, done)` if `passReqToCallback: true`\n\n### Example Configuration\n\n```typescript\nimport passport from 'passport';\nimport { Strategy, ExtractJwt, type JoseKey } from 'passport-jose';\n\n// Using a symmetric key (Uint8Array)\nconst secretKey: JoseKey = new TextEncoder().encode('your-256-bit-secret');\n\nconst options = {\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withSecretOrKey: secretKey,\n  algorithms: ['HS256'],\n  issuer: 'accounts.examplesoft.com',\n  audience: 'yoursite.net'\n};\n\npassport.use(new Strategy(options, (payload, done) => {\n  // payload is typed as jose.JWTPayload\n  // Note: User.findOne is pseudo-code - replace with your user lookup logic\n  User.findOne({ id: payload.sub }, (err, user) => {\n    if (err) return done(err, false);\n    if (user) return done(null, user);\n    return done(null, false);\n  });\n}));\n```\n\n### Using Different Key Formats\n\n```typescript\n// JWK format\nconst jwkKey: JoseKey = {\n  kty: 'RSA',\n  use: 'sig',\n  n: '...',\n  e: 'AQAB'\n};\n\n// Web Crypto API key\nconst cryptoKey: JoseKey = await crypto.subtle.importKey(/* ... */);\n\n// Node.js KeyObject\nconst keyObject: JoseKey = crypto.createSecretKey(Buffer.from('secret'));\n```\n\n### JWT Extraction Methods\n\nThe JWT must be extracted from the request using a user-supplied extractor function passed as the `jwtFromRequest` parameter.\n\n#### Included Extractors\n\n* `ExtractJwt.fromHeader(header_name)` - Extracts JWT from the specified HTTP header\n* `ExtractJwt.fromBodyField(field_name)` - Extracts JWT from the request body field\n* `ExtractJwt.fromAuthHeaderAsBearerToken()` - Extracts JWT from Authorization header with Bearer scheme (**recommended**)\n* `ExtractJwt.fromExtractors([extractors])` - Tries multiple extractors in sequence\n\n#### Custom Extractor Example\n\n```typescript\nconst cookieExtractor = (req: any): string | null => {\n  let token = null;\n  if (req && req.cookies) {\n    token = req.cookies['jwt'];\n  }\n  return token;\n};\n\nconst options = {\n  jwtFromRequest: cookieExtractor,\n  withSecretOrKey: secretKey\n};\n```\n\n### Authenticate Requests\n\nUse `passport.authenticate()` specifying `'jwt'` as the strategy:\n\n```typescript\napp.post('/profile',\n  passport.authenticate('jwt', { session: false }),\n  (req, res) => {\n    res.send(req.user.profile);\n  }\n);\n```\n\n### Include JWT in Requests\n\nWhen using `ExtractJwt.fromAuthHeaderAsBearerToken()`, include the JWT in the Authorization header:\n\n```\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n## Advanced Topics\n\n### Remote JWKS Integration\n\n```typescript\nimport { Strategy, ExtractJwt, fromRemoteJwks } from 'passport-jose';\n\n// Auth0 JWKS integration\nconst auth0Strategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://dev-example.auth0.com/.well-known/jwks.json', {\n    cacheMaxAge: 600000, // 10 minutes\n    cooldownDuration: 30000, // 30 seconds\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://dev-example.auth0.com/',\n  audience: 'https://api.myapp.com'\n}, (payload, done) => {\n  User.findById(payload.sub, done);\n});\n\n// Azure AD JWKS integration\nconst azureStrategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://login.microsoftonline.com/tenant/discovery/v2.0/keys', {\n    cacheMaxAge: 300000, // 5 minutes\n    timeoutDuration: 10000 // 10 seconds\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://login.microsoftonline.com/tenant/v2.0'\n}, (payload, done) => {\n  User.findById(payload.sub || payload.oid, done);\n});\n```\n\n#### Basic JWKS Usage\n\n```typescript\nimport { Strategy, ExtractJwt, fromRemoteJwks } from 'passport-jose';\n\n// Auth0 integration\nconst strategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://your-domain.auth0.com/.well-known/jwks.json', {\n    cacheMaxAge: 600000, // 10 minutes\n    cooldownDuration: 30000, // 30 seconds between requests\n    timeoutDuration: 5000, // 5 seconds request timeout\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://your-domain.auth0.com/',\n  audience: 'your-api-identifier'\n}, (payload, done) => {\n  User.findById(payload.sub, done);\n});\n```\n\n#### Popular Identity Provider Configurations\n\n```typescript\n// Example verify function (implement according to your user model)\nconst verifyUser = (payload, done) => {\n  User.findById(payload.sub, (err, user) => {\n    if (err) return done(err, false);\n    if (user) return done(null, user);\n    return done(null, false);\n  });\n};\n\n// Auth0\nconst auth0Strategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://dev-example.auth0.com/.well-known/jwks.json', {\n    cacheMaxAge: 600000,\n    cooldownDuration: 30000,\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://dev-example.auth0.com/',\n  audience: 'https://api.myapp.com'\n}, verifyUser);\n\n// Azure Active Directory\nconst azureStrategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://login.microsoftonline.com/common/discovery/v2.0/keys', {\n    cacheMaxAge: 300000, // 5 minutes (Azure keys rotate frequently)\n    timeoutDuration: 10000,\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://login.microsoftonline.com/{tenant}/v2.0'\n}, verifyUser);\n\n// AWS Cognito\nconst cognitoStrategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json', {\n    cacheMaxAge: 3600000, // 1 hour\n    cooldownDuration: 60000,\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://cognito-idp.{region}.amazonaws.com/{userPoolId}'\n}, verifyUser);\n\n// Google Identity Platform\nconst googleStrategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: fromRemoteJwks('https://www.googleapis.com/oauth2/v3/certs', {\n    cacheMaxAge: 86400000, // 24 hours\n    cooldownDuration: 30000,\n  }),\n  algorithms: ['RS256'],\n  issuer: 'https://accounts.google.com'\n}, verifyUser);\n```\n\n#### JWKS Configuration Options\n\n```typescript\ninterface RemoteJWKSetOptions {\n  /**\n   * Duration for which the JWKS is cached (default: 600000ms / 10 minutes)\n   */\n  cacheMaxAge?: number;\n\n  /**\n   * Cooldown period between JWKS requests (default: 30000ms / 30 seconds)\n   */\n  cooldownDuration?: number;\n\n  /**\n   * HTTP request timeout for JWKS fetching (default: 5000ms / 5 seconds)\n   */\n  timeoutDuration?: number;\n\n  /**\n   * HTTP agent for custom connection handling\n   */\n  agent?: any;\n\n  /**\n   * Additional headers to include in JWKS requests\n   */\n  headers?: Record<string, string>;\n}\n```\n\n### Multi-tenant Support\n\n```typescript\nimport { Strategy, ExtractJwt, type SecretOrKeyProvider } from 'passport-jose';\nimport { decodeProtectedHeader } from 'jose';\n\nconst keyProvider: SecretOrKeyProvider = (request, rawJwtToken, done) => {\n  // Extract tenant from JWT header or request\n  const decoded = decodeProtectedHeader(rawJwtToken);\n  const tenantId = decoded.kid || request.headers['x-tenant-id'];\n\n  // Fetch tenant-specific key\n  getTenantKey(tenantId)\n    .then(key => done(null, key))\n    .catch(err => done(err));\n};\n\nconst strategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withKeyProvider: keyProvider,\n  algorithms: ['RS256', 'ES256'],\n  issuer: 'https://auth.myapp.com'\n}, (payload, done) => {\n  // Verify user with tenant context\n  User.findInTenant(payload.tenant, payload.sub, done);\n});\n```\n\n### EdDSA Keys\n\n```typescript\nimport { generateKeyPair } from 'crypto';\nimport { Strategy, ExtractJwt } from 'passport-jose';\n\n// Generate EdDSA key pair\nconst { publicKey, privateKey } = generateKeyPair('ed25519', {\n  publicKeyEncoding: { type: 'spki', format: 'pem' },\n  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n});\n\nconst strategy = new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withSecretOrKey: publicKey,\n  algorithms: ['EdDSA']\n}, (payload, done) => {\n  User.findById(payload.sub, done);\n});\n```\n\n### Custom JWT Extractors\n\n```typescript\nconst cookieExtractor = (req: any): string | null => {\n  let token = null;\n  if (req && req.cookies) {\n    token = req.cookies['jwt'];\n  }\n  return token;\n};\n\nconst options = {\n  jwtFromRequest: cookieExtractor,\n  withSecretOrKey: secretKey\n};\n```\n\n## Framework Integration\n\n### NestJS Integration\n\nHere's how to integrate `passport-jose` with NestJS:\n\n```typescript\n// auth/jwt.strategy.ts\nimport { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ConfigService } from '@nestjs/config';\nimport { Strategy, ExtractJwt, fromRemoteJwks } from 'passport-jose';\n\nconst CACHE_MAX_AGE = 600_000; // 10 minutes\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor(configService: ConfigService) {\n    const jwksUrl = configService.get<string>('IDENTITY_PROVIDER_URL') + '/.well-known/jwks.json';\n\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      withKeyProvider: fromRemoteJwks(jwksUrl, { cacheMaxAge: CACHE_MAX_AGE }),\n      algorithms: ['RS256'],\n      issuer: configService.get<string>('JWT_ISSUER'),\n      audience: configService.get<string>('JWT_AUDIENCE'),\n    });\n  }\n\n  validate({ sub, email }: { sub: string; email: string }) {\n    return { userId: sub, email };\n  }\n}\n\n// auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { JwtStrategy } from './jwt.strategy';\n\n@Module({\n  providers: [JwtStrategy],\n})\nexport class AuthModule {}\n\n// types/express.d.ts - Type augmentation for Express\ndeclare namespace Express {\n  namespace Request {\n    interface User {\n      userId: string;\n      email: string;\n    }\n  }\n\n  interface Request {\n    user?: Request.User;\n  }\n}\n\ntype ContextUser = Express.Request.User;\n\n// middleware/auth/auth.guard.ts - HTTP Authentication Guards\nimport { Injectable, ExecutionContext, UseGuards } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class HttpAuthGuard extends AuthGuard('jwt') {\n  getRequest(context: ExecutionContext) {\n    return context.switchToHttp().getRequest();\n  }\n}\n\n@Injectable()\nexport class HttpOptionalAuthGuard extends HttpAuthGuard {\n  handleRequest<TUser>(err: any, user: TUser): TUser | null {\n    if (err) {\n      throw err;\n    }\n    return user;\n  }\n}\n\n// Guard Decorators\nexport const WithAuth = UseGuards(HttpAuthGuard);\nexport const WithOptionalAuth = UseGuards(HttpOptionalAuthGuard);\n\n// middleware/auth/current-user.decorator.ts - Current user decorator\nimport { createParamDecorator, ExecutionContext } from '@nestjs/common';\n\nexport const CurrentUser = createParamDecorator(\n  (_: unknown, context: ExecutionContext): ContextUser => {\n    return context.switchToHttp().getRequest().user;\n  },\n);\n\n// app.controller.ts - Example HTTP Controller Usage\nimport { Controller, Get } from '@nestjs/common';\nimport { WithAuth, WithOptionalAuth } from './middleware/auth/auth.guard';\nimport { CurrentUser } from './middleware/auth/current-user.decorator';\n\n@Controller('api')\nexport class AppController {\n  @Get('profile')\n  @WithAuth\n  getProfile(@CurrentUser() user: ContextUser) {\n    return {\n      message: 'Protected route',\n      user,\n    };\n  }\n\n  @Get('dashboard')\n  @WithOptionalAuth\n  getDashboard(@CurrentUser() user: ContextUser | null) {\n    return {\n      message: user ? 'Authenticated dashboard' : 'Public dashboard',\n      user,\n    };\n  }\n\n  @Get('public')\n  getPublic() {\n    return { message: 'Public route' };\n  }\n}\n\n// app.module.ts\nimport { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { AuthModule } from './auth/auth.module';\nimport { AppController } from './app.controller';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true,\n    }),\n    AuthModule,\n  ],\n  controllers: [AppController],\n})\nexport class AppModule {}\n```\n\n**Environment variables (.env):**\n```env\nIDENTITY_PROVIDER_URL=https://auth.example.com\nJWT_ISSUER=https://auth.example.com\nJWT_AUDIENCE=my-api\n```\n\n**Migration from `@nestjs/passport` + `passport-jwt`:**\n\n1. Replace `passport-jwt` with `passport-jose`\n2. Update strategy options: `secretOrKey` → `withSecretOrKey`\n3. Consider using `fromRemoteJwks()` for better key management\n4. Add required `algorithms` array\n5. Replace `ignoreExpiration` with `maxTokenAge` if needed\n\n### Express.js Integration\n\n```typescript\nimport express from 'express';\nimport passport from 'passport';\nimport { Strategy, ExtractJwt } from 'passport-jose';\n\nconst app = express();\n\npassport.use('jwt', new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withSecretOrKey: new TextEncoder().encode(process.env.JWT_SECRET),\n  algorithms: ['HS256'],\n  issuer: process.env.JWT_ISSUER,\n  maxTokenAge: '1h'\n}, async (payload, done) => {\n  try {\n    const user = await User.findById(payload.sub);\n    if (!user) return done(null, false, { message: 'User not found' });\n    return done(null, user);\n  } catch (error) {\n    return done(error);\n  }\n}));\n\n// Protected route with custom error handling\napp.get('/api/profile',\n  passport.authenticate('jwt', { session: false }),\n  (req, res) => {\n    res.json({ user: req.user });\n  }\n);\n\n// Custom error handler for JWT failures\napp.use((err, req, res, next) => {\n  if (err.name === 'JWTInvalid' || err.name === 'JWTExpired') {\n    return res.status(401).json({ error: 'Invalid or expired token' });\n  }\n  next(err);\n});\n```\n\n### GraphQL Integration\n\n```typescript\nimport { ApolloServer } from 'apollo-server-express';\nimport passport from 'passport';\nimport { Strategy, ExtractJwt } from 'passport-jose';\n\npassport.use(new Strategy({\n  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n  withSecretOrKey: new TextEncoder().encode(process.env.JWT_SECRET),\n  algorithms: ['HS256']\n}, (payload, done) => {\n  User.findById(payload.sub, done);\n}));\n\nconst server = new ApolloServer({\n  typeDefs,\n  resolvers,\n  context: ({ req }) => {\n    return new Promise((resolve, reject) => {\n      passport.authenticate('jwt', { session: false }, (err, user) => {\n        if (err) return reject(err);\n        resolve({ user, req });\n      })(req);\n    });\n  }\n});\n```\n\n## Migration from passport-jwt\n\nThis library is **not** a drop-in replacement for passport-jwt. Key differences:\n\n### What's Changed\n- **Property Names**: `secretOrKey` → `withSecretOrKey`, `secretOrKeyProvider` → `withKeyProvider`\n- **Library**: Uses `jose` library instead of `jsonwebtoken`\n- **Authentication**: Only supports Bearer token authentication\n- **Expiration**: Removed `ignoreExpiration` option (use `maxTokenAge` instead)\n- **Headers**: Removed `fromAuthHeaderWithScheme` (use Bearer tokens only)\n- **Keys**: Different key format support (`jose` native types)\n- **JWKS**: Added remote JWKS support with `fromRemoteJwks()`\n\n### Migration Steps\n1. **Update imports**: `passport-jwt` → `passport-jose`\n2. **Update property names**:\n   - `secretOrKey` → `withSecretOrKey`\n   - `secretOrKeyProvider` → `withKeyProvider`\n3. **Convert keys** to `jose`-compatible formats (CryptoKey, KeyObject, JWK, Uint8Array)\n4. **Replace options**:\n   - `ignoreExpiration` → `maxTokenAge`\n   - Add required `algorithms` array\n5. **Use Bearer extraction**: `ExtractJwt.fromAuthHeaderAsBearerToken()`\n6. **Add JWKS support**: Consider using `fromRemoteJwks()` for production\n7. **Update TypeScript types**: Import types from `passport-jose`\n\n## Troubleshooting\n\n### Common Issues\n\n#### \"Invalid JWT\" errors\n- Ensure your JWT token is properly formatted and signed with the correct key\n- Verify that the algorithm specified in `algorithms` array matches the JWT's signing algorithm\n- Check that the JWT hasn't expired (use `maxTokenAge` to control this)\n\n#### \"No auth token\" errors\n- Verify that your `jwtFromRequest` extractor is correctly configured\n- For Bearer tokens, ensure the Authorization header format is: `Authorization: Bearer <token>`\n- Check that the token is being included in the request\n\n#### Type errors with keys\n```typescript\n// ❌ Wrong - raw string\nwithSecretOrKey: 'my-secret'\n\n// ✅ Correct - Uint8Array for symmetric keys\nwithSecretOrKey: new TextEncoder().encode('my-secret')\n\n// ✅ Correct - for asymmetric keys\nwithSecretOrKey: fs.readFileSync('public-key.pem')\n\n// ✅ Best - JWKS for production\nwithKeyProvider: fromRemoteJwks('https://auth.example.com/.well-known/jwks.json', {\n  cacheMaxAge: 600000\n})\n```\n\n#### Claims validation failures\n- When using `issuer`, `audience`, or `subject` options, ensure your JWTs include these claims\n- Use `clockTolerance` option if you're experiencing time-related validation issues\n\n### Debugging Tips\n\n1. **Enable debug logging**: Set `DEBUG=passport-jose:*` environment variable\n2. **Test JWT tokens**: Use [jwt.io](https://jwt.io) to decode and verify your tokens\n3. **Check extractor**: Test your `jwtFromRequest` function independently:\n   ```typescript\n   const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);\n   console.log('Extracted token:', token);\n   ```\n4. **Validate keys**: Ensure your signing and verification keys match:\n   ```typescript\n   // For symmetric keys, both should be identical\n   const signingKey = new TextEncoder().encode('secret');\n   const verificationKey = new TextEncoder().encode('secret');\n\n   // For asymmetric keys, public key verifies what private key signed\n   ```\n5. **Check claims**: Log the payload in your verify callback:\n   ```typescript\n   passport.use(new Strategy(options, (payload, done) => {\n     console.log('JWT Payload:', payload);\n     // ... rest of verification\n   }));\n   ```\n\n### Environment-Specific Issues\n\n#### Development vs Production\n- Development: Consider using longer `maxTokenAge` for easier testing\n- Production: Use shorter expiration times and implement refresh token patterns\n\n#### CORS and Preflight Requests\n- Ensure your CORS configuration allows Authorization headers\n- Preflight OPTIONS requests don't include Authorization headers\n\n#### Load Balancers and Proxies\n- Verify that Authorization headers are forwarded correctly\n- Some load balancers may strip or modify headers\n\n## API Reference\n\n### Strategy Options\n\n```typescript\ninterface StrategyOptions {\n  jwtFromRequest: JwtFromRequestFunction;\n  withSecretOrKey?: JoseKey;\n  withKeyProvider?: SecretOrKeyProvider;\n  issuer?: string | string[];\n  audience?: string | string[];\n  algorithms?: string[];\n  subject?: string;\n  maxTokenAge?: string | number;\n  clockTolerance?: string | number;\n  typ?: string;\n  passReqToCallback?: boolean;\n}\n```\n\n### Type Definitions\n\n```typescript\nimport type { CryptoKey, KeyObject, JWK, JWTVerifyGetKey } from 'jose';\n\n// Re-exported `jose` types\ntype JoseKey = CryptoKey | KeyObject | JWK | Uint8Array;\n\ninterface JwtFromRequestFunction<T = any> {\n  (req: T): string | null;\n}\n\ninterface SecretOrKeyProvider<T = any> {\n  (request: T, rawJwtToken: string, done: (err: Error | string | null, secretOrKey?: JoseKey | JWTVerifyGetKey) => void): void;\n}\n\n// JWKS Provider function\nfunction fromRemoteJwks(\n  jwksUri: string,\n  options: RemoteJWKSetOptions\n): SecretOrKeyProvider;\n```\n\n## Development\n\n### Build and Test\n\n```bash\n# Install dependencies\nyarn install\n\n# Build TypeScript\nyarn build\n\n# Run tests\nyarn test\n\n# Run tests with coverage\nyarn test:coverage\n```\n\n### Requirements\n\n- Node.js 20+ (minimum required version)\n- TypeScript 5.0+ for development\n\n### Performance Characteristics\n\n- **JWT Verification**: ~10-50μs per token (varies by algorithm and key type)\n- **JWKS Caching**: Configurable cache reduces remote key fetches\n- **Memory Usage**: Minimal overhead with efficient key caching\n- **Bundle Size**: ~150KB total (including dependencies)\n\n### Compatibility\n\n- **Node.js**: 20.0.0+\n- **TypeScript**: 5.0+\n- **Passport**: 0.4.0+\n- **JOSE Library**: 6.0.0+\n\n## Security Considerations\n\n### Production Best Practices\n\n- **HTTPS Only**: Always use HTTPS in production to prevent token interception\n- **Strong Secrets**: Use cryptographically strong, randomly generated secrets (minimum 256 bits for HS256)\n- **Key Rotation**: Implement regular key rotation strategies, especially for symmetric keys\n- **Token Expiration**: Set appropriate token expiration times with `maxTokenAge` (recommend 15-60 minutes for access tokens)\n- **Algorithm Whitelist**: Always specify the `algorithms` array to prevent algorithm confusion attacks\n- **Claim Validation**: Validate all JWT claims that are relevant to your application security model\n\n### Key Management\n\n```typescript\n// ✅ Good: Use strong, randomly generated secrets\nconst secret = crypto.randomBytes(32); // 256 bits\n\n// ✅ Better: Use asymmetric keys for distributed systems\nconst { publicKey, privateKey } = generateKeyPair('ed25519');\n\n// ✅ Best: Use JWKS for production environments\nwithKeyProvider: fromRemoteJwks('https://auth.example.com/.well-known/jwks.json')\n```\n\n### Common Security Vulnerabilities\n\n- **Algorithm Confusion**: Prevented by specifying `algorithms` array\n- **Key Confusion**: Use different keys for different purposes\n- **Timing Attacks**: The `jose` library provides constant-time comparisons\n- **Token Replay**: Consider implementing nonce/jti claims for critical operations\n\n### Monitoring and Logging\n\n- Log authentication failures for security monitoring\n- Monitor for unusual token usage patterns\n- Set up alerts for JWKS endpoint failures\n- Track token expiration and refresh patterns\n\n## License\n\nThe [MIT License](http://opensource.org/licenses/MIT)\n\nCopyright (c) 2025 asyne\n\n## Credits\n\nThis project is inspired by and builds upon the excellent work of [Mike Nicholson](https://github.com/mikenicholson) and the original [passport-jwt](https://github.com/mikenicholson/passport-jwt) library. We're grateful for the foundation provided by the original passport-jwt project.\n","readmeFilename":"README.md"}