{"_id":"@carisls/sso-resource-api","_rev":"8-78451bf4e2140c49599085f43132563e","name":"@carisls/sso-resource-api","dist-tags":{"latest":"1.3.0"},"versions":{"1.0.0":{"name":"@carisls/sso-resource-api","version":"1.0.0","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.0.0","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"18e2919e7471f9eee6e1de3ea0a018a6fa23e7cb","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.0.0.tgz","fileCount":5,"integrity":"sha512-Kl11Iluw5UNb19W8SPpqzf/oloWXi/tkxWA3uRJfeyMiG52reMZmPCTqF4CQtu38uwHN8J7QRMosln+oC5WLOw==","signatures":[{"sig":"MEUCIQDNBfyiTUHCvgm5Lv1+YVAK9tRgTL0oKDGI96cZPQFEWwIgHYguWQP9mRy6hmp++sTdzuIe7ddqRmgl+i9WqOSXmSE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":6288},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"b38739a039702f128a698fb22968ea4148d5534e","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},"_npmVersion":"10.8.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"22.7.0","dependencies":{"@carisls/sso-core":"^1.0.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.9.1","neostandard":"^0.11.4"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.0.0_1724871683455_0.5220974294492144","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"@carisls/sso-resource-api","version":"1.1.0","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.1.0","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"bef689ea65c15bf56e708f30fdfe78ee7212f5b0","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.1.0.tgz","fileCount":5,"integrity":"sha512-Um6PwAzPvna983iL6MDGV8E/tFn/e8AaY+1hqp2MeIAA7MvLKtgjxw3GWVNWjlROTRcCz2jVYKPFoZaqe1f2+w==","signatures":[{"sig":"MEUCIG5G98HPXXanOLXj9lLvA9zOVoo/AVgxGO4HR2VLHfeVAiEA+qERh4H4H8nQepqio6YRf4Hm538oVANTWV7JyjTP0UU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6289},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"5a2ab9404fd2425186937f632b7cba1b94522f98","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},"_npmVersion":"10.9.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"22.13.1","dependencies":{"@carisls/sso-core":"^1.1.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.18.0","neostandard":"^0.12.0"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.1.0_1737697257632_0.4378504716425473","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@carisls/sso-resource-api","version":"1.1.1","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.1.1","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"cc5409fa8e75061f6494679500691e3625acec85","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.1.1.tgz","fileCount":5,"integrity":"sha512-yqaJdBIlpkOs5tNQ1WkbkqVak2vyHX+Ks+bNX52fp6AokMn7KusKwTd1U4MCYte4HG1cMZr8wJyL6A7EoREjRg==","signatures":[{"sig":"MEQCICFn5bcb4BVvPGYkBxEftz0TXtC+ujkQt5whyAakZ13sAiAFPQ9K0eIq2Cv+g0txVN9B5gdTh8SJxmCM7iDBLeE6tg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6289},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"9d191e16d996db7a1ad91c944fb73d06063a2ca6","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},"_npmVersion":"10.9.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"22.13.1","dependencies":{"@carisls/sso-core":"^1.1.2"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.18.0","neostandard":"^0.12.0"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.1.1_1737735859872_0.9116073392842436","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@carisls/sso-resource-api","version":"1.1.2","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.1.2","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"101c3e5c0af406af091ed20fb2a1b680a026479a","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.1.2.tgz","fileCount":5,"integrity":"sha512-EuxOeXzExNksoxK6u/bOqyP4hU/VRs33TjWJywCOwRaYlm4Wh6a3aGz0Z1sScicWv/eZP7dTKQZtFD38HjxA+g==","signatures":[{"sig":"MEQCICkZq0yJ3kT2+OMuguEnsAKaCzKlwQHm48s6VS4NPqbLAiB9aD55MlklX8K1ZovmDybK9qFx3scTRV+XOh0RdtJLYw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6289},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"2125bf2292cb2ff22ebe566456006d7ae1b3772c","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},"_npmVersion":"10.9.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@carisls/sso-core":"^1.1.3"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.24.0","neostandard":"^0.12.1"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.1.2_1744757863412_0.33818333329611083","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@carisls/sso-resource-api","version":"1.2.0","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.2.0","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"49b7c11d309d3dc649068813d22bd75f81c39686","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.2.0.tgz","fileCount":6,"integrity":"sha512-ZpQdSyNAxZANzTo0zML0DYczP2bLkxGCISxVJIlQt63qmGLuYzcYC/p9Dz4KOiCBpQDHPfpZpQ1V0bANyX63vg==","signatures":[{"sig":"MEUCIDcb1/RJUrWbL9any+yiG4jKf9mnbP5dSpB8YScvonuhAiEApMJ2T+zlInrF74d9MfQsMp4xxtBHgnThoAIhsiNvJnc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16741},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"c284f5f2af830e0920a2847546b798ab091586f4","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:73c4401c-fb62-48fb-aa8d-7a20b2841215"}},"_npmVersion":"11.6.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@carisls/sso-core":"^1.2.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.39.2","neostandard":"^0.12.2"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.2.0_1766785028259_0.7971022435584161","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@carisls/sso-resource-api","version":"1.2.1","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.2.1","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"3445369068730f2802544e1861daa79c169bf1d7","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.2.1.tgz","fileCount":6,"integrity":"sha512-OFjH0RPxARh18RHf+LOk3dmBxUtqacDoPKLxOWVAHO1S8FF+xgLYwfxgSJSfVee76euIJA2nu9lyBczsQhsZVQ==","signatures":[{"sig":"MEUCIQDAWX8aaq7yzFVtGhhGvKR5YKEJr8YlbiXRdrDqZEEHAQIgTQrxDK4V40op4R9CzBIcCsd1oe+/3HVxmW7/ecmr7A8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16429},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"48b9bd4759d9d51cdedc317154b0ef1b36a408fb","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:73c4401c-fb62-48fb-aa8d-7a20b2841215"}},"_npmVersion":"11.6.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@carisls/sso-core":"^1.2.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.39.2","neostandard":"^0.12.2"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.2.1_1767103567079_0.36386646330754724","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@carisls/sso-resource-api","version":"1.2.2","keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","_id":"@carisls/sso-resource-api@1.2.2","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"dist":{"shasum":"6f4f3c500f40d6b95f597d7142dc1d364a7abb72","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.2.2.tgz","fileCount":6,"integrity":"sha512-hjwIQZVLnEAAvcp24idGKxkkAowcnTRocnJfTxeWzSXsivnf05fTbbbp5EvSYUauBl2dwmdWrPDvhwsx7JmQgg==","signatures":[{"sig":"MEUCIFfVb5ETQwx0YO1xgpazSVGYrkxdDBOMGzfEl31C2wTBAiEA2nwKuco1mTWiNvbqP3xVndM+ePpL2Id5ipJ78TYeHXc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16518},"main":"cjs/index.js","type":"module","module":"esm/index.js","exports":{".":{"import":"./esm/index.js","require":"./cjs/index.cjs"}},"gitHead":"0975c01d97cd7bc840ec0f8349d11b027d5c3a36","scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:73c4401c-fb62-48fb-aa8d-7a20b2841215"}},"_npmVersion":"11.6.2","description":"A middleware implementing resource api SSO","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@carisls/sso-core":"^1.2.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.39.2","neostandard":"^0.12.2"},"_npmOperationalInternal":{"tmp":"tmp/sso-resource-api_1.2.2_1767105667834_0.48303031053061996","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@carisls/sso-resource-api","version":"1.3.0","description":"A middleware implementing resource api SSO","main":"cjs/index.js","module":"esm/index.js","type":"module","exports":{".":{"require":"./cjs/index.cjs","import":"./esm/index.js"}},"scripts":{"test":"npm run test:lint","test:lint":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'","test:lint-fix":"eslint 'esm/**/*.js' 'cjs/**/*.cjs'"},"keywords":["sso","openid","okta","keycloak"],"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","dependencies":{"@carisls/sso-core":"^1.3.0"},"devDependencies":{"eslint":"^9.39.2","neostandard":"^0.12.2"},"gitHead":"32d4d12769d9c1747ff35cbea59d174156b7f98e","_id":"@carisls/sso-resource-api@1.3.0","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-m1wju1DVEmAPiHlv+fBnR2U5q/UuI0rF04mpJjgoC+JiJRzRwH59+LA4Rg1btimwaPNqtzXW6psI25XxfuKqgA==","shasum":"25f67301ab0cad9d4380118bc1ad216f878c9882","tarball":"https://registry.npmjs.org/@carisls/sso-resource-api/-/sso-resource-api-1.3.0.tgz","fileCount":6,"unpackedSize":16520,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGNC2TxCbgVwItDRtv+up/CyrdveppyywLrWj7/kYT9oAiEA/7ueEUICAjRLG5udkZbH8vlJPgsdEUrOTOqJIuyZCB0="}]},"_npmUser":{"name":"GitLab CI/CD","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"gitlab","oidcConfigId":"oidc:73c4401c-fb62-48fb-aa8d-7a20b2841215"}},"directories":{},"maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sso-resource-api_1.3.0_1769136584863_0.8422590143769644"},"_hasShrinkwrap":false}},"time":{"created":"2024-08-28T19:01:23.357Z","modified":"2026-01-23T02:49:45.142Z","1.0.0":"2024-08-28T19:01:23.622Z","1.1.0":"2025-01-24T05:40:57.832Z","1.1.1":"2025-01-24T16:24:20.061Z","1.1.2":"2025-04-15T22:57:43.586Z","1.2.0":"2025-12-26T21:37:08.403Z","1.2.1":"2025-12-30T14:06:07.242Z","1.2.2":"2025-12-30T14:41:07.994Z","1.3.0":"2026-01-23T02:49:44.998Z"},"author":{"name":"Mihovil Strujic","email":"mstrujic@carisls.com"},"license":"MIT","keywords":["sso","openid","okta","keycloak"],"description":"A middleware implementing resource api SSO","maintainers":[{"name":"mstrujic-caris","email":"mstrujic@carisls.com"},{"name":"michaelortho","email":"mihovil.strujic@gmail.com"}],"readme":"# @carisls/sso-resource-api\n\nA middleware implementing resource API SSO for Express.js applications. This package validates JWT tokens from Authorization headers and injects user information into requests. Perfect for API servers that receive tokens from authenticated clients.\n\n## Features\n\n- 🔐 JWT token validation from Authorization headers\n- 🔑 JWKS-based public key validation with caching\n- 👤 User token mapping and request injection\n- 🛡️ Built-in authorization middleware\n- 🌐 Multi-provider support (Keycloak, Okta, and other OIDC providers)\n- 📦 Supports both ESM and CommonJS\n- ⚡ Lightweight and performant\n- 🔒 Automatic token validation on each request\n\n## Installation\n\n```bash\nnpm install @carisls/sso-resource-api\n```\n\n## Quick Start\n\n### ESM (ECMAScript Modules)\n\n```javascript\nimport express from 'express';\nimport { router } from '@carisls/sso-resource-api';\n\nconst app = express();\n\napp.use(router({\n  // Simple format: comma-separated string\n  providers: 'https://auth.example.com',\n  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],\n}));\n\n// Protected route - user is automatically available via req.user\napp.get('/api/data', (req, res) => {\n  if (!req.user) {\n    return res.status(401).json({ error: 'Unauthorized' });\n  }\n  res.json({ message: 'Protected data', user: req.user });\n});\n\napp.listen(3000);\n```\n\n### CommonJS\n\n```javascript\nconst express = require('express');\nconst { router } = require('@carisls/sso-resource-api');\n\nconst app = express();\n\napp.use(router({\n  // Simple format: comma-separated string\n  providers: 'https://auth.example.com',\n  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],\n}));\n\n// Protected route - user is automatically available via req.user\napp.get('/api/data', (req, res) => {\n  if (!req.user) {\n    return res.status(401).json({ error: 'Unauthorized' });\n  }\n  res.json({ message: 'Protected data', user: req.user });\n});\n\napp.listen(3000);\n```\n\n## API Reference\n\n### `router(options)`\n\nCreates Express middleware that validates JWT tokens from Authorization headers and injects user information into requests.\n\n**Parameters:**\n\n- `options` (Object): Configuration object with the following properties:\n  - `providers` (string | Array<Object>, **required**): Provider configuration(s). Can be:\n    - A comma-separated string of provider URLs (e.g., `'https://auth1.example.com,https://auth2.example.com'`)\n    - An array of provider configuration objects:\n      - `ssoUrl` (string): Base URL for the provider (usually equal to `iss`). Used to discover OpenID Connect configuration\n      - `iss` (string, optional): Issuer identifier. If not provided, defaults to `ssoUrl`\n      - `publicKey` (string, optional): Static public key in PEM format (if not using JWKS)\n  - `publicKeyCache` (number, optional): Public key caching expiration in seconds (default: `300`)\n  - `expOffset` (number, optional): Force renewal of tokens earlier (in seconds) to handle clock skew issues (default: `0`)\n  - `userMapper` (function, optional): Custom function to map tokens to user object. Signature: `(token) => userObject`\n\n**Returns:** Express middleware function `(req, res, next) => void`\n\nThe middleware:\n\n- Validates JWT tokens from `Authorization: Bearer <token>` headers\n- On successful validation, sets `req.user` with user information\n- On failed validation, logs error but continues (does not block request - you can check `req.user` in your routes)\n- Sets `req.token` with the validated token\n\n**Example:**\n\n```javascript\nimport express from 'express';\nimport { router } from '@carisls/sso-resource-api';\n\nconst app = express();\n\napp.use(router({\n  // Simple format: comma-separated string (iss defaults to ssoUrl)\n  providers: 'https://auth.example.com',\n  // Or detailed format: array of objects\n  // providers: [\n  //   {\n  //     ssoUrl: 'https://auth.example.com',\n  //     // iss defaults to ssoUrl if not provided\n  //   }\n  // ],\n  publicKeyCache: 600,\n  userMapper: (token) => {\n    return {\n      id: token.sub,\n      email: token.email,\n      name: token.name,\n      roles: token.roles || []\n    };\n  }\n}));\n\n// Protected route - check req.user to verify authentication\napp.get('/api/users', (req, res) => {\n  if (!req.user) {\n    return res.status(401).json({ error: 'Unauthorized' });\n  }\n  res.json({ users: [], user: req.user });\n});\n\n// Access token in route\napp.get('/api/profile', (req, res) => {\n  if (!req.user) {\n    return res.status(401).json({ error: 'Unauthorized' });\n  }\n  res.json({ \n    user: req.user,\n    token: req.token // Access the validated token if needed\n  });\n});\n\napp.listen(3000);\n```\n\n### `authorize(role, exceptions, redirectToLogin)`\n\nExpress.js middleware for authorization filtering based on user roles. This middleware works in conjunction with the router to provide role-based access control.\n\n**Parameters:**\n\n- `role` (string | string[] | undefined, optional): Role(s) to filter by. If `undefined`, only checks for authenticated user.\n- `exceptions` (string[] | undefined, optional): Array of URL paths to skip authorization checks.\n- `redirectToLogin` (boolean, default: `false`): If `true`, redirects to login page instead of returning 401.\n\n**Returns:** Express middleware function `(req, res, next) => void`\n\n**Example:**\n\n```javascript\nimport express from 'express';\nimport { router, authorize } from '@carisls/sso-resource-api';\n\nconst app = express();\n\n// Setup SSO router\napp.use(router({\n  // Simple format: comma-separated string\n  providers: 'https://auth.example.com',\n  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],\n}));\n\n// Require any authenticated user\napp.use(authorize());\n\n// Require specific role\napp.get('/api/admin', authorize('admin'), (req, res) => {\n  res.json({ message: 'Admin access granted', user: req.user });\n});\n\n// Require one of multiple roles\napp.get('/api/dashboard', authorize(['admin', 'user']), (req, res) => {\n  res.json({ message: 'Dashboard access', user: req.user });\n});\n\n// With exceptions and redirect\napp.use(authorize('user', ['/api/public', '/api/health'], false));\n\napp.listen(3000);\n```\n\n## Complete Example\n\n```javascript\nimport express from 'express';\nimport { router, authorize } from '@carisls/sso-resource-api';\n\nconst app = express();\n\n// Configure SSO middleware\napp.use(router({\n  // Simple format: comma-separated string (iss defaults to ssoUrl)\n  providers: process.env.SSO_URL,\n  // Or array format with custom iss:\n  // providers: [\n  //   {\n  //     ssoUrl: process.env.SSO_URL,\n  //     iss: process.env.SSO_ISSUER // optional, defaults to ssoUrl\n  //   }\n  // ],\n  publicKeyCache: 600\n}));\n\n// Public routes (no authentication required)\napp.get('/api/health', (req, res) => {\n  res.json({ status: 'ok' });\n});\n\n// Protected routes - require authentication\napp.get('/api/dashboard', authorize(), (req, res) => {\n  res.json({\n    message: 'Dashboard',\n    user: req.user\n  });\n});\n\n// Admin routes - require admin role\napp.get('/api/admin', authorize('admin'), (req, res) => {\n  res.json({\n    message: 'Admin panel',\n    user: req.user\n  });\n});\n\n// API routes with role-based access\napp.get('/api/users', authorize(['admin', 'user-manager']), (req, res) => {\n  res.json({ users: [] });\n});\n\napp.listen(3000, () => {\n  console.log('Server running on http://localhost:3000');\n});\n```\n\n## How It Works\n\n1. **Token Validation**: On each request, the middleware checks for an `Authorization: Bearer <token>` header.\n\n2. **Token Parsing**: If present, the token is extracted from the header.\n\n3. **Token Validation**: The token is validated against the configured identity provider(s) using JWKS:\n   - The issuer is identified from the token\n   - The appropriate provider's public key is fetched and cached\n   - Token signature, expiration, and issuer are validated\n\n4. **User Injection**: On successful validation:\n   - `req.user` is set with user information (mapped from the token)\n   - `req.token` is set with the validated token\n\n5. **Error Handling**: On validation failure, an error is logged but the request continues. Your routes should check `req.user` to determine if authentication was successful.\n\n## Supported Providers\n\nThis package works with any OIDC-compliant identity provider, including:\n\n- **Keycloak**\n- **Okta**\n- **Auth0**\n- **Azure AD**\n- **Google Identity Platform**\n- Any other OIDC/OAuth2 provider\n\n## User Object Structure\n\nBy default, the `req.user` object follows this structure (can be customized with `userMapper`):\n\n```typescript\n{\n  iss: string;              // Issuer\n  id: string;               // User ID (from 'sub')\n  sid?: string;             // Session ID\n  sa: boolean;              // Service account flag\n  azp?: string;             // Authorized party\n  name?: {                  // Name object (if available)\n    full: string;\n    familyName: string;\n    givenName: string;\n  };\n  email?: string;           // Email (if available)\n  roles: string[];          // User roles\n}\n```\n\n## Environment Variables\n\nFor production use, store sensitive values in environment variables:\n\n```bash\nSSO_URL=https://auth.example.com\nSSO_ISSUER=https://auth.example.com\n```\n\n## Security Considerations\n\n- **Token Validation**: All tokens are validated using JWKS before use\n- **Public Key Caching**: Public keys are cached to reduce network requests and improve performance\n- **No Token Storage**: This package does not store tokens - it only validates them from request headers\n- **Authorization Header**: Tokens must be sent in the standard `Authorization: Bearer <token>` format\n\n## Differences from @carisls/sso-standard\n\nThis package is designed for **resource API servers** that receive tokens from authenticated clients:\n\n- ✅ Validates tokens from Authorization headers\n- ✅ No login/logout flows (handled by client)\n- ✅ No cookie management\n- ✅ Lightweight and focused on token validation\n- ✅ Perfect for microservices and API gateways\n\nUse `@carisls/sso-standard` if you need:\n\n- Complete OAuth2 authorization code flow\n- Cookie-based session management\n- Login/logout endpoints\n- Automatic token refresh\n\n## Dependencies\n\n- `@carisls/sso-core`: Core SSO utilities (token validation, issuer selection, etc.)\n\n## License\n\nMIT\n\n## Author\n\nMihovil Strujic <mstrujic@carisls.com>\n","readmeFilename":"README.md"}