fix(security): upgrade better-auth family to 1.7.0-rc.4

Fixes the @better-auth/oauth-provider advisory (unbound resource
indicators could yield access tokens for unauthorized audiences,
Dependabot #55). No patched 1.6.x exists; 1.7.0-rc.4 is the first
patched line.

The 1.7 oauth-provider expects a wider schema: new nullable columns on
oauth_clients / oauth_access_tokens / oauth_refresh_tokens /
oauth_consents (back-channel logout, DPoP, resource indicators, refresh
token rotation) and three new tables (oauth_resources,
oauth_client_resources, oauth_client_assertions). Migration 0014 is
purely additive; validate-migrations gains the matching upgrade fixture.
This commit is contained in:
Arunavo Ray
2026-08-06 07:00:03 +05:30
parent 185946984b
commit 2f6af22e25
7 changed files with 2981 additions and 22 deletions
+21 -19
View File
@@ -9,8 +9,8 @@
"@astrojs/mdx": "^7.0.3",
"@astrojs/node": "^11.0.2",
"@astrojs/react": "^6.0.1",
"@better-auth/oauth-provider": "1.6.23",
"@better-auth/sso": "1.6.23",
"@better-auth/oauth-provider": "1.7.0-rc.4",
"@better-auth/sso": "1.7.0-rc.4",
"@octokit/plugin-throttling": "^11.0.3",
"@octokit/rest": "^22.0.1",
"@radix-ui/react-accordion": "^1.2.16",
@@ -39,7 +39,7 @@
"@types/react-dom": "^19.2.3",
"astro": "^7.1.0",
"bcryptjs": "^3.0.3",
"better-auth": "1.6.23",
"better-auth": "1.7.0-rc.4",
"buffer": "^6.0.3",
"canvas-confetti": "^1.9.4",
"class-variance-authority": "^0.7.1",
@@ -190,23 +190,23 @@
"@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"@better-auth/core": ["@better-auth/core@1.6.23", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "@cloudflare/workers-types": ">=4", "@opentelemetry/api": "^1.9.0", "better-call": "1.3.7", "jose": "^6.1.0", "kysely": "^0.28.5 || ^0.29.0", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types", "@opentelemetry/api"] }, "sha512-beEhOs0uVeOxYOZKUfIEBd/nQV2Bd4/6wyLxZ0OFkn6CMTK2Vi+hXuZLnyPBeB6RdHpebEoJWiHqwHxBIxgPDQ=="],
"@better-auth/core": ["@better-auth/core@1.7.0-rc.4", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.41.1", "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "@cloudflare/workers-types": ">=4", "@opentelemetry/api": "^1.9.0", "better-call": "1.3.7", "jose": "^6.1.0", "kysely": "^0.28.5 || ^0.29.0", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types", "@opentelemetry/api"] }, "sha512-hkxBHcEXU6qxGd08ovBVuaSsENB78A45sclB5dEbohUMckkCbTab1eydGknsMF7SfE/vGcgPER5vzAQwNzP9oQ=="],
"@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "drizzle-orm": "^0.45.2" }, "optionalPeers": ["drizzle-orm"] }, "sha512-2+/PTVfIP9E7iz6af8TB3lhnowHUj9ljC66kECmHaFEdUqPgzHoWux9epotKwO7XDg2ui4ttWQ8CMeNFLvQeKQ=="],
"@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0" }, "optionalPeers": ["drizzle-orm"] }, "sha512-UpBwR54jBJALnwqcezGS+CYj2i3qF6bl5PAzL8o0WDQleN6QHmqOC6fUHq8+las6R4Lj6BRozdUzbE4DaGusfg=="],
"@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "kysely": "^0.28.17 || ^0.29.0" }, "optionalPeers": ["kysely"] }, "sha512-zbNJsMbG09exfkGyvFqBLLqWoMPAUWjxCuUnEK5AsjbYoZeIjj/QGZgdf4CapVWryKxjA9Q6Jlr6fbiPpC3VAg=="],
"@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "kysely": "^0.28.17 || ^0.29.0" }, "optionalPeers": ["kysely"] }, "sha512-JNApE34ATqfxMfOLyE+e4KwqZzg7ZkhcN4gnKNuLIQPq7ja/NTt5FnZCgbFCOviGmN5kfOWIvpRyp/hW+YjLjA=="],
"@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2" } }, "sha512-krIiR0pIVkaKlAzm690n5bcMW4NGbqeMg0HQSD9fz/KcQF/eWLqcq9gG/BhHTj2i/y96qH+W5JWPmaSOS5iTgQ=="],
"@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2" } }, "sha512-/yIudwUCWRTEOyZteZ1dqa0cEk5/Dot4WiIw4TlMsGB2Rk0/HIVqtBULBWW551ihefWrz9AKGuFVtXQhRMXAZw=="],
"@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "mongodb": "^6.0.0 || ^7.0.0" }, "optionalPeers": ["mongodb"] }, "sha512-7+QdevitGlKBbP6JbiSk5SBnzPsKV/mDrQBGBn8hwByQLeJwqpqbuBPw7ZI8vzUlFfAAnyFiqwP3Eb8mxnp7pA=="],
"@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "mongodb": "^6.0.0 || ^7.0.0" }, "optionalPeers": ["mongodb"] }, "sha512-BRGwL0HfTa2hWW0WIHlsXpCBqwXVJUR6gQkaLA2Bm9a76KLaPVWLzigZJIfcVFZLaQJrFQ1ZdIh/zqbfC8m4Dw=="],
"@better-auth/oauth-provider": ["@better-auth/oauth-provider@1.6.23", "", { "dependencies": { "jose": "^6.1.3", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "better-auth": "^1.6.23", "better-call": "1.3.7" } }, "sha512-1sDN+N4Sztmpk8ziCU3MXicxOTfvYoHvHvhJMQ7PSfr+pLXnYN+dJFI9S3zBRwstmTeJx/OhRIZWrwFJ0TgBnA=="],
"@better-auth/oauth-provider": ["@better-auth/oauth-provider@1.7.0-rc.4", "", { "dependencies": { "jose": "^6.2.3", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "better-auth": "^1.7.0-rc.4", "better-call": "1.3.7" } }, "sha512-7br1e+gJsFAC0EB4IDuEefF005CeaB8hbY59c8FMpcqiR5Vp+8mT2e8dmYSSjfH13Y34ObGR+ORI7mGQhzxlHQ=="],
"@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@prisma/client", "prisma"] }, "sha512-2qSdzidq4tkb1eS5TTqb4Nzg0mdZWm3Qky9SYeXeb8PpVQbC2sxqJhEM5mK7y12uU6I8hc64wO9f7AFVNL+6UQ=="],
"@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@prisma/client", "prisma"] }, "sha512-SOmE17lirhGIXAJdvlThgNjt57Z98N5CewVFNRiPGHOv2w7llR3Fc6ASvoUTClB4pP0YyBjNZZwLVCwEoAKxwQ=="],
"@better-auth/sso": ["@better-auth/sso@1.6.23", "", { "dependencies": { "fast-xml-parser": "^5.8.0", "jose": "^6.1.3", "samlify": "^2.13.1", "tldts": "^6.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "better-auth": "^1.6.23", "better-call": "1.3.7" } }, "sha512-nAO25rH25SL2t/BkK/iPqGsnhwI7tOGxktVupuyIBysju13QpV4tJjytnSbVnnDwPo5p6M4Ld6WF83XCEJYCzg=="],
"@better-auth/sso": ["@better-auth/sso@1.7.0-rc.4", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "fast-xml-parser": "^5.8.0", "jose": "^6.2.3", "samlify": "^2.13.1", "tldts": "^7.4.3", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "better-auth": "^1.7.0-rc.4", "better-call": "1.3.7" } }, "sha512-8mROv9XEbVyqqVVb7pXoTL/2mOulFuGLgiAf5DJA+Z0SOTDMATrNbb17pyqISMwHE5xiwqwpp2ZiaxkWVN2wtQ=="],
"@better-auth/telemetry": ["@better-auth/telemetry@1.6.23", "", { "peerDependencies": { "@better-auth/core": "^1.6.23", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1" } }, "sha512-/R2Kb+z2BpDOOWwVHqOk+c0VNpuwfCv4Hp5Yr9003WIZPax/zyNraGLB9CFE8qF2gZW8Dsz419k4I8CPrGzpDA=="],
"@better-auth/telemetry": ["@better-auth/telemetry@1.7.0-rc.4", "", { "peerDependencies": { "@better-auth/core": "^1.7.0-rc.4", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1" } }, "sha512-IZM3cDmLCbrmdRtBKEJtZ6Gqmfu2RBvai0DLEzXBs6/nTG5BVk3oz7JbcITAdE0AoMCV8rMdZJ3C1k/nIhZdDg=="],
"@better-auth/utils": ["@better-auth/utils@0.4.2", "", { "dependencies": { "@noble/hashes": "^2.0.1" } }, "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A=="],
@@ -400,9 +400,9 @@
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
"@noble/ciphers": ["@noble/ciphers@2.1.1", "", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="],
"@noble/ciphers": ["@noble/ciphers@2.2.0", "", {}, "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA=="],
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
"@noble/hashes": ["@noble/hashes@2.2.0", "", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="],
"@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="],
@@ -852,7 +852,7 @@
"before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
"better-auth": ["better-auth@1.6.23", "", { "dependencies": { "@better-auth/core": "1.6.23", "@better-auth/drizzle-adapter": "1.6.23", "@better-auth/kysely-adapter": "1.6.23", "@better-auth/memory-adapter": "1.6.23", "@better-auth/mongo-adapter": "1.6.23", "@better-auth/prisma-adapter": "1.6.23", "@better-auth/telemetry": "1.6.23", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "better-call": "1.3.7", "defu": "^6.1.4", "jose": "^6.1.3", "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.1.1", "zod": "^4.3.6" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": "^0.45.2", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-4vOaRd9UiKGKm9R+ej0jjU1es3MiJIiNc9Qq3VCnYqOZ4/nb5272QqTxWYoDxyUXl5x6A2x2we5KZKQO9teTQQ=="],
"better-auth": ["better-auth@1.7.0-rc.4", "", { "dependencies": { "@better-auth/core": "1.7.0-rc.4", "@better-auth/drizzle-adapter": "1.7.0-rc.4", "@better-auth/kysely-adapter": "1.7.0-rc.4", "@better-auth/memory-adapter": "1.7.0-rc.4", "@better-auth/mongo-adapter": "1.7.0-rc.4", "@better-auth/prisma-adapter": "1.7.0-rc.4", "@better-auth/telemetry": "1.7.0-rc.4", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.1", "@noble/ciphers": "^2.2.0", "@noble/hashes": "^2.2.0", "better-call": "1.3.7", "defu": "^6.1.4", "jose": "^6.2.3", "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.3.0", "zod": "^4.3.6" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4 || >=1.0.0-beta.1", "drizzle-orm": "^0.45.2", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-1ONP6b9715zc/NqQV2LFpk7HYakjOUtPeXYuBI20ou6tY8zQ5VUYQYJ65GBXnDYDua9CSrre9CbuYkZ8FpnzfQ=="],
"better-call": ["better-call@1.3.7", "", { "dependencies": { "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w=="],
@@ -1126,7 +1126,7 @@
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jose": ["jose@6.2.1", "", {}, "sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw=="],
"jose": ["jose@6.2.8", "", {}, "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
@@ -1328,7 +1328,7 @@
"nanoid": ["nanoid@6.0.0", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-mkUH+rPkwU2qPadJ0oJZOjeZ5Mxn8Q1UhevwkTRWNuUZzyia3h4rhzK39hxaHTk0o2OxB8W2SQ6A8k23ZDi1pQ=="],
"nanostores": ["nanostores@1.2.0", "", {}, "sha512-F0wCzbsH80G7XXo0Jd9/AVQC7ouWY6idUCTnMwW5t/Rv9W8qmO6endavDwg7TNp5GbugwSukFMVZqzPSrSMndg=="],
"nanostores": ["nanostores@1.4.2", "", {}, "sha512-Wxv8Roefr2nqtiRG0bnaFlpYqpIVtOEeJZHaH+4nGgOK1/7n6OHOuHCb/bhqrNQgZM8fyd0s1PqhdrJc9Ib44g=="],
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
@@ -1566,9 +1566,9 @@
"tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="],
"tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="],
"tldts": ["tldts@7.4.10", "", { "dependencies": { "tldts-core": "^7.4.10" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog=="],
"tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
"tldts-core": ["tldts-core@7.4.10", "", {}, "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw=="],
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
@@ -1750,6 +1750,8 @@
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@better-auth/utils/@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
"@bruits/satteri-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
"@bruits/satteri-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="],
+57
View File
@@ -0,0 +1,57 @@
CREATE TABLE `oauth_client_assertions` (
`id` text PRIMARY KEY NOT NULL,
`expires_at` integer NOT NULL
);
--> statement-breakpoint
CREATE TABLE `oauth_client_resources` (
`id` text PRIMARY KEY NOT NULL,
`client_id` text NOT NULL,
`resource_id` text NOT NULL,
`metadata` text,
`created_at` integer DEFAULT (unixepoch())
);
--> statement-breakpoint
CREATE INDEX `idx_oauth_client_resources_client_id` ON `oauth_client_resources` (`client_id`);--> statement-breakpoint
CREATE INDEX `idx_oauth_client_resources_resource_id` ON `oauth_client_resources` (`resource_id`);--> statement-breakpoint
CREATE TABLE `oauth_resources` (
`id` text PRIMARY KEY NOT NULL,
`identifier` text NOT NULL,
`name` text NOT NULL,
`access_token_ttl` integer,
`refresh_token_ttl` integer,
`signing_algorithm` text,
`signing_key_id` text,
`allowed_scopes` text,
`custom_claims` text,
`dpop_bound_access_tokens_required` integer,
`disabled` integer,
`policy_version` integer,
`metadata` text,
`created_at` integer DEFAULT (unixepoch()),
`updated_at` integer DEFAULT (unixepoch())
);
--> statement-breakpoint
CREATE UNIQUE INDEX `oauth_resources_identifier_unique` ON `oauth_resources` (`identifier`);--> statement-breakpoint
CREATE INDEX `idx_oauth_resources_identifier` ON `oauth_resources` (`identifier`);--> statement-breakpoint
ALTER TABLE `oauth_access_tokens` ADD `authorization_code_id` text;--> statement-breakpoint
ALTER TABLE `oauth_access_tokens` ADD `resources` text;--> statement-breakpoint
ALTER TABLE `oauth_access_tokens` ADD `requested_user_info_claims` text;--> statement-breakpoint
ALTER TABLE `oauth_access_tokens` ADD `revoked` integer;--> statement-breakpoint
ALTER TABLE `oauth_access_tokens` ADD `confirmation` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `client_discovery_id` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `client_credentials_scopes` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `backchannel_logout_uri` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `backchannel_logout_session_required` integer;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `application_type` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `jwks` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `jwks_uri` text;--> statement-breakpoint
ALTER TABLE `oauth_clients` ADD `dpop_bound_access_tokens` integer;--> statement-breakpoint
ALTER TABLE `oauth_consents` ADD `resources` text;--> statement-breakpoint
ALTER TABLE `oauth_consents` ADD `requested_user_info_claims` text;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `authorization_code_id` text;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `resources` text;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `requested_user_info_claims` text;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `rotated_at` integer;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `rotation_replay_response` text;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `rotation_replay_expires_at` integer;--> statement-breakpoint
ALTER TABLE `oauth_refresh_tokens` ADD `confirmation` text;
File diff suppressed because it is too large Load Diff
+7
View File
@@ -99,6 +99,13 @@
"when": 1780377747526,
"tag": "0013_slim_galactus",
"breakpoints": true
},
{
"idx": 14,
"version": "6",
"when": 1785979662457,
"tag": "0014_fancy_speed_demon",
"breakpoints": true
}
]
}
+3 -3
View File
@@ -58,8 +58,8 @@
"@astrojs/mdx": "^7.0.3",
"@astrojs/node": "^11.0.2",
"@astrojs/react": "^6.0.1",
"@better-auth/oauth-provider": "1.6.23",
"@better-auth/sso": "1.6.23",
"@better-auth/oauth-provider": "1.7.0-rc.4",
"@better-auth/sso": "1.7.0-rc.4",
"@octokit/plugin-throttling": "^11.0.3",
"@octokit/rest": "^22.0.1",
"@radix-ui/react-accordion": "^1.2.16",
@@ -88,7 +88,7 @@
"@types/react-dom": "^19.2.3",
"astro": "^7.1.0",
"bcryptjs": "^3.0.3",
"better-auth": "1.6.23",
"better-auth": "1.7.0-rc.4",
"buffer": "^6.0.3",
"canvas-confetti": "^1.9.4",
"class-variance-authority": "^0.7.1",
+75
View File
@@ -294,6 +294,77 @@ function verify0013Migration(db: any) {
assert(normName.dflt_value === null, `Expected normalized_name to have no default, got ${normName.dflt_value}`);
}
function seedPre0014Database(db: any) {
// Migrations 0000-0013 have run, so the OAuth provider tables are in their
// better-auth 1.6 shape. Seed a row in each altered table so the 1.7
// column-adds can be verified against real data.
db.run("INSERT INTO users (id, email, username, name) VALUES ('u-14', 'u14@example.com', 'u14', 'User Fourteen')");
db.run("INSERT INTO oauth_clients (id, client_id, redirect_uris) VALUES ('app-14', 'client-14', '[\"https://example.com/cb\"]')");
db.run("INSERT INTO oauth_access_tokens (id, token, client_id, user_id, scopes) VALUES ('at-14', 'access-14', 'client-14', 'u-14', '[\"openid\"]')");
db.run("INSERT INTO oauth_refresh_tokens (id, token, client_id, user_id, scopes) VALUES ('rt-14', 'refresh-14', 'client-14', 'u-14', '[\"openid\"]')");
db.run("INSERT INTO oauth_consents (id, client_id, user_id, scopes) VALUES ('co-14', 'client-14', 'u-14', '[\"openid\"]')");
}
function verify0014Migration(db: any) {
// Columns added for @better-auth/oauth-provider 1.7, all nullable so
// pre-existing rows are untouched.
const expectedNewColumns: Record<string, string[]> = {
oauth_clients: [
"client_discovery_id",
"client_credentials_scopes",
"backchannel_logout_uri",
"backchannel_logout_session_required",
"application_type",
"jwks",
"jwks_uri",
"dpop_bound_access_tokens",
],
oauth_access_tokens: [
"authorization_code_id",
"resources",
"requested_user_info_claims",
"revoked",
"confirmation",
],
oauth_refresh_tokens: [
"authorization_code_id",
"resources",
"requested_user_info_claims",
"rotated_at",
"rotation_replay_response",
"rotation_replay_expires_at",
"confirmation",
],
oauth_consents: ["resources", "requested_user_info_claims"],
};
for (const [table, columns] of Object.entries(expectedNewColumns)) {
const cols = db
.query(`PRAGMA table_info(${table})`)
.all() as Array<{ name: string; notnull: number }>;
for (const column of columns) {
const col = cols.find((c) => c.name === column);
assert(col, `Expected ${table}.${column} column to exist`);
assert(col.notnull === 0, `Expected ${table}.${column} to be nullable`);
}
}
// Seeded rows survive the column adds.
for (const [table, id] of [
["oauth_clients", "app-14"],
["oauth_access_tokens", "at-14"],
["oauth_refresh_tokens", "rt-14"],
["oauth_consents", "co-14"],
] as const) {
const row = db.query(`SELECT id FROM ${table} WHERE id = '${id}'`).get();
assert(row, `Expected ${table} row '${id}' to survive migration`);
}
// The three new 1.7 tables exist and accept rows.
db.run("INSERT INTO oauth_resources (id, identifier, name) VALUES ('res-14', 'https://api.example.com', 'Example API')");
db.run("INSERT INTO oauth_client_resources (id, client_id, resource_id) VALUES ('cr-14', 'client-14', 'https://api.example.com')");
db.run("INSERT INTO oauth_client_assertions (id, expires_at) VALUES ('jti-14', 1234567890)");
}
const MIGRATION_0012_TIMESTAMP = 1774062000000;
const MIGRATION_0013_TIMESTAMP = 1780377747526;
@@ -409,6 +480,10 @@ const latestUpgradeFixtures: Record<string, UpgradeFixture> = {
seed: seedPre0013Database,
verify: verify0013Migration,
},
"0014_fancy_speed_demon": {
seed: seedPre0014Database,
verify: verify0014Migration,
},
};
function lintMigrations(selectedMigrations: Migration[]) {
+72
View File
@@ -678,6 +678,16 @@ export const oauthClients = sqliteTable("oauth_clients", {
public: integer("public", { mode: "boolean" }),
type: text("type"),
requirePKCE: integer("require_pkce", { mode: "boolean" }),
// Added by @better-auth/oauth-provider 1.7 (client discovery, client
// credentials grant, OIDC back-channel logout, private_key_jwt, DPoP).
clientDiscoveryId: text("client_discovery_id"),
clientCredentialsScopes: text("client_credentials_scopes"), // JSON string[]
backchannelLogoutUri: text("backchannel_logout_uri"),
backchannelLogoutSessionRequired: integer("backchannel_logout_session_required", { mode: "boolean" }),
applicationType: text("application_type"),
jwks: text("jwks"),
jwksUri: text("jwks_uri"),
dpopBoundAccessTokens: integer("dpop_bound_access_tokens", { mode: "boolean" }),
referenceId: text("reference_id"),
metadata: text("metadata"), // JSON
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
@@ -699,6 +709,13 @@ export const oauthAccessTokens = sqliteTable("oauth_access_tokens", {
expiresAt: integer("expires_at", { mode: "timestamp" }),
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
scopes: text("scopes").notNull(), // JSON string[]
// Added by @better-auth/oauth-provider 1.7 (resource indicators, token
// revocation on session end, DPoP proof binding).
authorizationCodeId: text("authorization_code_id"),
resources: text("resources"), // JSON string[]
requestedUserInfoClaims: text("requested_user_info_claims"), // JSON string[]
revoked: integer("revoked", { mode: "timestamp" }),
confirmation: text("confirmation"), // JSON
}, (table) => [
index("idx_oauth_access_tokens_token").on(table.token),
index("idx_oauth_access_tokens_client_id").on(table.clientId),
@@ -718,6 +735,15 @@ export const oauthRefreshTokens = sqliteTable("oauth_refresh_tokens", {
revoked: integer("revoked", { mode: "timestamp" }),
authTime: integer("auth_time", { mode: "timestamp" }),
scopes: text("scopes").notNull(), // JSON string[]
// Added by @better-auth/oauth-provider 1.7 (resource indicators, refresh
// token rotation with replay detection, DPoP proof binding).
authorizationCodeId: text("authorization_code_id"),
resources: text("resources"), // JSON string[]
requestedUserInfoClaims: text("requested_user_info_claims"), // JSON string[]
rotatedAt: integer("rotated_at", { mode: "timestamp" }),
rotationReplayResponse: text("rotation_replay_response"),
rotationReplayExpiresAt: integer("rotation_replay_expires_at", { mode: "timestamp" }),
confirmation: text("confirmation"), // JSON
}, (table) => [
index("idx_oauth_refresh_tokens_token").on(table.token),
index("idx_oauth_refresh_tokens_client_id").on(table.clientId),
@@ -731,6 +757,9 @@ export const oauthConsents = sqliteTable("oauth_consents", {
userId: text("user_id").references(() => users.id),
referenceId: text("reference_id"),
scopes: text("scopes").notNull(), // JSON string[]
// Added by @better-auth/oauth-provider 1.7 (resource indicators).
resources: text("resources"), // JSON string[]
requestedUserInfoClaims: text("requested_user_info_claims"), // JSON string[]
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
updatedAt: integer("updated_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
}, (table) => [
@@ -738,6 +767,49 @@ export const oauthConsents = sqliteTable("oauth_consents", {
index("idx_oauth_consents_user_id").on(table.userId),
]);
// OAuth protected resources (RFC 8707 resource indicators, new in
// @better-auth/oauth-provider 1.7). Empty unless resources are registered;
// the 1.7 fix for unbound resource indicators only issues audience-restricted
// tokens for resources listed here.
export const oauthResources = sqliteTable("oauth_resources", {
id: text("id").primaryKey(),
identifier: text("identifier").notNull().unique(),
name: text("name").notNull(),
accessTokenTtl: integer("access_token_ttl"),
refreshTokenTtl: integer("refresh_token_ttl"),
signingAlgorithm: text("signing_algorithm"),
signingKeyId: text("signing_key_id"),
allowedScopes: text("allowed_scopes"), // JSON string[]
customClaims: text("custom_claims"), // JSON
dpopBoundAccessTokensRequired: integer("dpop_bound_access_tokens_required", { mode: "boolean" }),
disabled: integer("disabled", { mode: "boolean" }),
policyVersion: integer("policy_version"),
metadata: text("metadata"), // JSON
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
updatedAt: integer("updated_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
}, (table) => [
index("idx_oauth_resources_identifier").on(table.identifier),
]);
// Which clients may request which resources (new in 1.7).
export const oauthClientResources = sqliteTable("oauth_client_resources", {
id: text("id").primaryKey(),
clientId: text("client_id").notNull(),
resourceId: text("resource_id").notNull(),
metadata: text("metadata"), // JSON
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`(unixepoch())`),
}, (table) => [
index("idx_oauth_client_resources_client_id").on(table.clientId),
index("idx_oauth_client_resources_resource_id").on(table.resourceId),
]);
// Replay prevention for private_key_jwt / client_secret_jwt client assertions
// (new in 1.7): the row id is the assertion's jti, kept until expiry.
export const oauthClientAssertions = sqliteTable("oauth_client_assertions", {
id: text("id").primaryKey(),
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
});
// JWKS keypairs for signing OIDC id_tokens (better-auth `jwt` plugin).
// Model name "jwks" pluralizes to the binding name "jwkss" under usePlural,
// while the physical table stays "jwks".