{"_id":"@ascendenceai/cortena-extensions-auth","_rev":"2-894b2aa3ba32fe26d4a69bca0f994414","name":"@ascendenceai/cortena-extensions-auth","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@ascendenceai/cortena-extensions-auth","version":"0.1.0","license":"SEE LICENSE IN LICENSE","_id":"@ascendenceai/cortena-extensions-auth@0.1.0","maintainers":[{"name":"amit_ascendence","email":"connect@mindmentors.net"}],"homepage":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions#readme","bugs":{"url":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions/issues"},"dist":{"shasum":"f0d122419600038b222654c9d01409b554a5dcbe","tarball":"https://registry.npmjs.org/@ascendenceai/cortena-extensions-auth/-/cortena-extensions-auth-0.1.0.tgz","fileCount":6,"integrity":"sha512-W/veeP9Mww47nq6lICx+oJwst7SzgJwxPchmGfmn9wxF47ZDBS6IFJHTHkC6LoPsdeSwaeSRPVahPhPr6Cwkbw==","signatures":[{"sig":"MEUCIHMGQ+BVGP/jCeldeCtpkslOqgm2u+vq8nS51pmJLnYHAiEAoSnHJGOzK425Z+01ui8+QgYCMDlG1yCcr6s2QGNkX6w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30215},"main":"dist/index.js","type":"module","_from":"file:ascendenceai-cortena-extensions-auth-0.1.0.tgz","types":"dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"tsc --noEmit -p tsconfig.test.json","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit -p tsconfig.test.json"},"_npmUser":{"name":"amit_ascendence","email":"connect@mindmentors.net"},"_resolved":"/private/var/folders/yz/wdclk8jx2l3c4bkzs3wg_0z80000gp/T/5bee97a7bbcd1ff43acee3349dea2bea/ascendenceai-cortena-extensions-auth-0.1.0.tgz","_integrity":"sha512-W/veeP9Mww47nq6lICx+oJwst7SzgJwxPchmGfmn9wxF47ZDBS6IFJHTHkC6LoPsdeSwaeSRPVahPhPr6Cwkbw==","repository":{"url":"git+https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions.git","type":"git","directory":"packages/auth"},"_npmVersion":"11.9.0","description":"The server-side auth middleware of §2 and §4: cortena-auth JWT verification (RS256 via JWKS, HS256 fallback), requireOrgMatch, the licence check that fails closed, and the org-role guards.","directories":{},"_nodeVersion":"25.6.1","dependencies":{"jsonwebtoken":"^9.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/express":"^5.0.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"express":">=4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cortena-extensions-auth_0.1.0_1788785617800_0.9480479767163814","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"_id":"@ascendenceai/cortena-extensions-auth@0.4.0","bugs":{"url":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions/issues"},"dist":{"shasum":"24cdc00c4901cd9cdd3d5b7db0f775dc44b46fdd","tarball":"https://registry.npmjs.org/@ascendenceai/cortena-extensions-auth/-/cortena-extensions-auth-0.4.0.tgz","fileCount":6,"integrity":"sha512-vHhPC5QZtW5AAaUrRs67DJCmataVYxvEtaF7PCnRJgSGyx1bmq0hkw5NpChpzZ8C7uyrUND/2Deb2bY9kc53Vw==","signatures":[{"sig":"MEYCIQDZVaDGobBjoJQTvzQ2cPWKd057XCXIyVT8lTEV5q0hUAIhAJuhLV53DDNhaYzC0iNtgnLXqZSZo2CbqIKF2kBGRwOX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC33CxSOJ/3xxSapMyETC1i4xi4ydwvK9VMSXEFef6WGAiA4aCIIL5OEwTYLcRO0WvPV//KtnTmM9o5yh72+EiR3LQ=="}],"unpackedSize":30215},"main":"dist/index.js","name":"@ascendenceai/cortena-extensions-auth","type":"module","_from":"file:ascendenceai-cortena-extensions-auth-0.4.0.tgz","types":"dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"license":"SEE LICENSE IN LICENSE","scripts":{"lint":"tsc --noEmit -p tsconfig.test.json","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit -p tsconfig.test.json"},"version":"0.4.0","_npmUser":{"name":"amit_ascendence","email":"connect@mindmentors.net"},"homepage":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions#readme","_resolved":"/private/var/folders/yz/wdclk8jx2l3c4bkzs3wg_0z80000gp/T/dbe11a49056ff7fc26be78c615cdf405/ascendenceai-cortena-extensions-auth-0.4.0.tgz","_integrity":"sha512-vHhPC5QZtW5AAaUrRs67DJCmataVYxvEtaF7PCnRJgSGyx1bmq0hkw5NpChpzZ8C7uyrUND/2Deb2bY9kc53Vw==","repository":{"url":"git+https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions.git","type":"git","directory":"packages/auth"},"_npmVersion":"11.9.0","description":"The server-side auth middleware of §2 and §4: cortena-auth JWT verification (RS256 via JWKS, HS256 fallback), requireOrgMatch, the licence check that fails closed, and the org-role guards.","directories":{},"maintainers":[{"name":"amit_ascendence","email":"connect@mindmentors.net"}],"_nodeVersion":"25.6.1","dependencies":{"jsonwebtoken":"^9.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/express":"^5.0.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"express":">=4.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cortena-extensions-auth_0.4.0_1790491402282_0.24304321286620967"}}},"time":{"created":"2026-09-07T12:53:37.671Z","modified":"2026-09-27T06:43:22.530Z","0.1.0":"2026-09-07T12:53:37.936Z","0.4.0":"2026-09-27T06:43:22.367Z"},"bugs":{"url":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions/issues"},"license":"SEE LICENSE IN LICENSE","homepage":"https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions#readme","repository":{"url":"git+https://github.com/Ascendence-AI-Technology-Pvt-Ltd/cortena-extensions.git","type":"git","directory":"packages/auth"},"description":"The server-side auth middleware of §2 and §4: cortena-auth JWT verification (RS256 via JWKS, HS256 fallback), requireOrgMatch, the licence check that fails closed, and the org-role guards.","maintainers":[{"name":"amit_ascendence","email":"connect@mindmentors.net"}],"readme":"# `@ascendenceai/cortena-extensions-auth`\n\nThe server-side auth middleware of §2 and §4 of *How to create a Cortena\nextension* — the four things every extension backend currently writes by hand,\nwritten once.\n\n```ts\nimport { authenticate, requireOrgMatch, requireLicense } from '@ascendenceai/cortena-extensions-auth';\n\napp.get('/health', (_req, res) => res.json({ ok: true }));          // unauthenticated (§4)\napp.use('/v1/orgs/:orgId', authenticate, requireOrgMatch, requireLicense('tasks'), router);\n```\n\n| Export | What it does |\n| --- | --- |\n| `authenticate` | Verifies a cortena-auth JWT. RS256 against the JWKS at `${AUTH_SERVICE_URL}/.well-known/jwks.json` first, cached for an hour; HS256 against `JWT_SECRET` as the fallback. A delegated HS256 token minted by an extension for an agent is accepted only when `DELEGATION_ISSUER`/`DELEGATION_SECRET` are configured, and only with an `exp`. Puts the user on `req.user`. |\n| `requireOrgMatch` | 403 when the JWT's `orgId` is not the `:orgId` in the path. This is the IDOR guard: without it, a valid token for org A reads org B by editing the URL. |\n| `requireLicense(extensionId)` | Asks cortena-auth whether the org holds a licence for this extension, cached five minutes. **Fails closed** outside development — a licence service that cannot be reached is a 503, never an allow. |\n| `requireExtensionAdmin`, `requireOrgRole`, `requireMember`, `requireAdmin`, `requireOwner` | The org-role guards of §13. |\n| `isProduction`, `clearLicenseCache` | Environment predicate, and the cache reset a test needs. |\n| types | `CortenaUser`, `AuthenticatedRequest`, `LicenseInfo`, `OrgRole` |\n\n## Configuration (§19.1 — nothing environment-specific in source)\n\n| Variable | |\n| --- | --- |\n| `AUTH_SERVICE_URL` | cortena-auth's in-cluster address. Defaults to `http://localhost:3200` for local development. |\n| `JWT_SECRET` | The HS256 secret. **Required in production** — the process throws rather than falling back to the development string. |\n| `DELEGATION_ISSUER`, `DELEGATION_SECRET` | The pair that makes delegated agent tokens acceptable. Delegation is disabled, loudly, if the issuer is `cortena-auth` itself. |\n| `NODE_ENV`, `K_SERVICE` | Either marks the process as production. |\n\n## Two things it does that are easy to get wrong by hand\n\n**The licence check fails closed.** `requireLicense` returns 503 when it cannot\nreach cortena-auth, not 200. An extension that treats an unreachable licence\nservice as a pass is unlicensed-by-outage, and nothing in the pipeline says so.\n\n**A delegated token must carry `exp`.** `jsonwebtoken` only enforces expiry when\nthe claim is present, so a delegated token minted without one never expires.\nThis refuses it.\n\n## Known gap\n\nRefusals are `{ error, code? }`, not the §15.6 envelope\n`{ ok, status, code, message }`. The runtime half of audit rule P-22 asserts the\nenvelope on every error a caller can see, so an extension whose 401 comes from\nhere will fail that row. Changing the shape is a breaking change for the three\nextensions already on this package (flux, workflows, tally) and is tracked\nseparately — see the EXTBP-22 comment thread.\n","readmeFilename":"README.md"}