{"_id":"@boring-stack-pkg/eslint-plugin-oauth-security","_rev":"2-e2d423ea1d9c61256464845af2c86efb","name":"@boring-stack-pkg/eslint-plugin-oauth-security","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@boring-stack-pkg/eslint-plugin-oauth-security","version":"0.1.1","keywords":["eslint","eslintplugin","typescript","oauth","oidc","pkce","security"],"author":"","license":"MIT","_id":"@boring-stack-pkg/eslint-plugin-oauth-security@0.1.1","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"homepage":"https://github.com/AI-Starter-Templates/eslint-plugins#readme","bugs":{"url":"https://github.com/AI-Starter-Templates/eslint-plugins/issues"},"dist":{"shasum":"e48851469acb937db16657ee70c1227b727b30ce","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-oauth-security/-/eslint-plugin-oauth-security-0.1.1.tgz","fileCount":13,"integrity":"sha512-0vF74SrIxAOsDiJwN7cyMLCatWos0KMPw3BSgpZZXtMUNLqydiHc1zCljTUq4Lxq1r4drnIa7NYCeKGnfkpEyQ==","signatures":[{"sig":"MEUCIQD5CVOLO4oJ1Uo5W5vFYqn7Yu0uP6K5cypY9MPZBNQO7QIgfPF/HWbIcAacYrFB6/uaA+bUcgNPMT0nomkU9l/ch6Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boring-stack-pkg%2feslint-plugin-oauth-security@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":54065},"main":"./dist/index.cjs","type":"module","_from":"file:boring-stack-pkg-eslint-plugin-oauth-security-0.1.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"_resolved":"/tmp/e6cb4fec2adacd28a8389017247cf9eb/boring-stack-pkg-eslint-plugin-oauth-security-0.1.1.tgz","_integrity":"sha512-0vF74SrIxAOsDiJwN7cyMLCatWos0KMPw3BSgpZZXtMUNLqydiHc1zCljTUq4Lxq1r4drnIa7NYCeKGnfkpEyQ==","repository":{"url":"git+https://github.com/AI-Starter-Templates/eslint-plugins.git","type":"git","directory":"eslint-plugin-oauth-security"},"_npmVersion":"10.9.7","description":"ESLint rules enforcing security-critical OAuth invariants: Redis-backed state, PKCE for OIDC providers, and bounded state TTLs.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","dependencies":{"micromatch":"4.0.5","@typescript-eslint/utils":"8.0.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.0.0","eslint":"9.0.0","vitest":"2.0.0","@eslint/js":"9.0.0","typescript":"6.0.3","@types/node":"22.0.0","@types/micromatch":"4.0.9","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0"},"peerDependencies":{"eslint":"8.57.0 || ^9.0.0","typescript":">=5.0.0","@typescript-eslint/parser":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-plugin-oauth-security_0.1.1_1779219597259_0.9283352661069433","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@boring-stack-pkg/eslint-plugin-oauth-security","version":"0.1.2","description":"ESLint rules enforcing security-critical OAuth invariants: Redis-backed state, PKCE for OIDC providers, and bounded state TTLs.","type":"module","license":"MIT","author":"","repository":{"type":"git","url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","directory":"eslint-plugin-oauth-security"},"publishConfig":{"access":"public"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"keywords":["eslint","eslintplugin","typescript","oauth","oidc","pkce","security"],"peerDependencies":{"@typescript-eslint/parser":">=8.0.0","eslint":"8.57.0 || ^9.0.0","typescript":">=5.0.0"},"dependencies":{"@typescript-eslint/utils":"8.0.0","micromatch":"4.0.5"},"devDependencies":{"@eslint/js":"9.0.0","@types/micromatch":"4.0.9","@types/node":"22.0.0","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0","eslint":"9.0.0","tsup":"8.0.0","typescript":"6.0.3","vitest":"2.0.0"},"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest"},"_id":"@boring-stack-pkg/eslint-plugin-oauth-security@0.1.2","bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","_integrity":"sha512-jMrK6nnTSEERAIBLPNTj/6HZKkrb4OSqdf+n6HVzoTol+iSdjO2rOexFYtePae477Z6aHiRAxzK6DXPdl2grpQ==","_resolved":"/tmp/2f96ba63195dd5dbfaa035668955d965/boring-stack-pkg-eslint-plugin-oauth-security-0.1.2.tgz","_from":"file:boring-stack-pkg-eslint-plugin-oauth-security-0.1.2.tgz","_nodeVersion":"22.22.3","_npmVersion":"11.15.0","dist":{"integrity":"sha512-jMrK6nnTSEERAIBLPNTj/6HZKkrb4OSqdf+n6HVzoTol+iSdjO2rOexFYtePae477Z6aHiRAxzK6DXPdl2grpQ==","shasum":"53f433e3a8b7c2e08f7c0888fef7e73a99294fb1","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-oauth-security/-/eslint-plugin-oauth-security-0.1.2.tgz","fileCount":13,"unpackedSize":54353,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCj3WoDH1f3bj1gD4ibcKtA7PxDD/2wD2aus+oJAQJxKQIgIW7otiz2TXzFoAQKxekDS9jYWuDYtgy4hXoVzHHgCTE="}]},"_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"directories":{},"maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-plugin-oauth-security_0.1.2_1779695644237_0.21670362200550497"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-19T19:39:57.093Z","modified":"2026-05-25T07:54:04.542Z","0.1.1":"2026-05-19T19:39:57.421Z","0.1.2":"2026-05-25T07:54:04.384Z"},"bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"license":"MIT","homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","keywords":["eslint","eslintplugin","typescript","oauth","oidc","pkce","security"],"repository":{"type":"git","url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","directory":"eslint-plugin-oauth-security"},"description":"ESLint rules enforcing security-critical OAuth invariants: Redis-backed state, PKCE for OIDC providers, and bounded state TTLs.","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"readme":"# eslint-plugin-oauth-security\n\n[![npm](https://img.shields.io/npm/v/@boring-stack-pkg/eslint-plugin-oauth-security?logo=npm)](https://www.npmjs.com/package/@boring-stack-pkg/eslint-plugin-oauth-security) [![source](https://img.shields.io/badge/source-github-blue?logo=github)](https://github.com/boringstack-xyz/eslint-plugins/tree/main/eslint-plugin-oauth-security)\n\nESLint rules enforcing the security-critical OAuth invariants that lint\ncan catch statically:\n\n- **`state-must-be-redis-backed`** — OAuth state must live in Redis,\n  not in a signed cookie. Catches the \"stuff state into a cookie\"\n  anti-pattern that some tutorials still recommend.\n- **`pkce-required-for-oidc`** — OIDC providers (Google, Apple,\n  Microsoft, Auth0, Okta, Cognito) must use PKCE.\n  `<provider>.createAuthorizationURL(state, scopes)` without a\n  `code_verifier` is reported.\n- **`state-ttl-bounded`** — Redis state writes must use a short TTL\n  (default ≤ 10 min). Long-lived state widens the replay window\n  pointlessly.\n\n> All three rules are best-effort static analysis. They catch the\n> biggest classes of OAuth misconfig, but they can't replace\n> integration tests that verify the full handshake against a real IdP.\n\n## Install\n\n```sh\npnpm add -D @boring-stack-pkg/eslint-plugin-oauth-security\n```\n\nPeer deps: `eslint >= 8.57`, `@typescript-eslint/parser >= 8`,\n`typescript >= 5`.\n\n## Use (flat config)\n\n```js\nimport tsParser from \"@typescript-eslint/parser\";\nimport oauthSecurity from \"@boring-stack-pkg/eslint-plugin-oauth-security\";\n\nexport default [\n  {\n    files: [\"**/*.{ts,tsx}\"],\n    languageOptions: { parser: tsParser },\n    plugins: { \"oauth-security\": oauthSecurity },\n    rules: {\n      \"oauth-security/state-must-be-redis-backed\": \"error\",\n      \"oauth-security/pkce-required-for-oidc\": \"error\",\n      \"oauth-security/state-ttl-bounded\": [\"error\", { maxTtlSeconds: 600 }],\n    },\n  },\n];\n```\n\nOr use the bundled config:\n\n```js\nimport oauthSecurity from \"@boring-stack-pkg/eslint-plugin-oauth-security\";\n\nexport default [oauthSecurity.configs.recommended];\n```\n\n## Rules\n\n| Rule                                                                     | Description                              | Default in recommended |\n| ------------------------------------------------------------------------ | ---------------------------------------- | ---------------------- |\n| [`state-must-be-redis-backed`](docs/rules/state-must-be-redis-backed.md) | State must persist to Redis, not cookies | `error`                |\n| [`pkce-required-for-oidc`](docs/rules/pkce-required-for-oidc.md)         | OIDC providers must use PKCE             | `error`                |\n| [`state-ttl-bounded`](docs/rules/state-ttl-bounded.md)                   | State TTL ≤ configured maximum           | `error`                |\n\n## License\n\nMIT.\n","readmeFilename":"README.md"}