From 5532191ab59dd2f2b9c5822de7bcd21f0c67210c Mon Sep 17 00:00:00 2001 From: Chris Farhood Date: Sun, 5 Jul 2026 16:38:57 -0400 Subject: [PATCH] feat: use current @better-auth/oauth-provider (drop deprecated oidc-provider) Current OAuth 2.1 provider plugin (versioned with core, 1.6.23). Bundles JWT (access tokens verifiable at /jwks), DCR via /oauth2/register incl. unauthenticated registration (MCP clients register before they have creds), skipConsent since sign-in is the authorization for a personal connector. --- package-lock.json | 126 ++++++++++++++++++++++++++-------------------- package.json | 1 + src/auth.ts | 16 ++++-- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/package-lock.json b/package-lock.json index c5394d2..a724bd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "intervalsicu-mcp-auth", "version": "0.1.0", "dependencies": { + "@better-auth/oauth-provider": "^1.6.23", "better-auth": "^1.6.23", "pg": "^8.13.1" }, @@ -18,6 +19,67 @@ "typescript": "^5.7.2" } }, + "node_modules/@better-auth/core": { + "version": "1.6.23", + "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.23.tgz", + "integrity": "sha512-beEhOs0uVeOxYOZKUfIEBd/nQV2Bd4/6wyLxZ0OFkn6CMTK2Vi+hXuZLnyPBeB6RdHpebEoJWiHqwHxBIxgPDQ==", + "license": "MIT", + "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" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@better-auth/oauth-provider": { + "version": "1.6.23", + "resolved": "https://registry.npmjs.org/@better-auth/oauth-provider/-/oauth-provider-1.6.23.tgz", + "integrity": "sha512-1sDN+N4Sztmpk8ziCU3MXicxOTfvYoHvHvhJMQ7PSfr+pLXnYN+dJFI9S3zBRwstmTeJx/OhRIZWrwFJ0TgBnA==", + "license": "MIT", + "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" + } + }, + "node_modules/@better-auth/utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz", + "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.0.1" + } + }, + "node_modules/@better-fetch/fetch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz", + "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -503,7 +565,7 @@ "version": "22.20.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -513,7 +575,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz", "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -626,35 +688,6 @@ } } }, - "node_modules/better-auth/node_modules/@better-auth/core": { - "version": "1.6.23", - "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.23.tgz", - "integrity": "sha512-beEhOs0uVeOxYOZKUfIEBd/nQV2Bd4/6wyLxZ0OFkn6CMTK2Vi+hXuZLnyPBeB6RdHpebEoJWiHqwHxBIxgPDQ==", - "license": "MIT", - "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" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - } - } - }, "node_modules/better-auth/node_modules/@better-auth/drizzle-adapter": { "version": "1.6.23", "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.23.tgz", @@ -744,22 +777,7 @@ "@better-fetch/fetch": "1.3.1" } }, - "node_modules/better-auth/node_modules/@better-auth/utils": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz", - "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^2.0.1" - } - }, - "node_modules/better-auth/node_modules/@better-fetch/fetch": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz", - "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==", - "license": "MIT" - }, - "node_modules/better-auth/node_modules/better-call": { + "node_modules/better-call": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.7.tgz", "integrity": "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==", @@ -779,12 +797,6 @@ } } }, - "node_modules/better-auth/node_modules/set-cookie-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.1.tgz", - "integrity": "sha512-vM9SUhjsUYs6UeJUmygc5Ofm5eQGe85riob5ju6XCgFGJI5PLV4nrDAQpQjd+LkFBpAkADn5BQQpZ9EUNkyLuA==", - "license": "MIT" - }, "node_modules/defu": { "version": "6.1.7", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", @@ -1015,6 +1027,12 @@ "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", "license": "MIT" }, + "node_modules/set-cookie-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.1.tgz", + "integrity": "sha512-vM9SUhjsUYs6UeJUmygc5Ofm5eQGe85riob5ju6XCgFGJI5PLV4nrDAQpQjd+LkFBpAkADn5BQQpZ9EUNkyLuA==", + "license": "MIT" + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -1061,7 +1079,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/xtend": { diff --git a/package.json b/package.json index 2595d28..5f7d3f3 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { + "@better-auth/oauth-provider": "^1.6.23", "better-auth": "^1.6.23", "pg": "^8.13.1" }, diff --git a/src/auth.ts b/src/auth.ts index 9c04d83..1642e6c 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -12,7 +12,7 @@ * consistent across the product (no Authentik involved). */ import { betterAuth } from "better-auth"; -import { jwt, oidcProvider } from "better-auth/plugins"; +import { oauthProvider } from "@better-auth/oauth-provider"; import { Pool } from "pg"; function required(name: string): string { @@ -53,11 +53,19 @@ export const auth = betterAuth({ database: pool, socialProviders, plugins: [ - jwt(), - oidcProvider({ + // Current OAuth 2.1 provider (replaces the deprecated oidc-provider). + // Bundles the JWT plugin, so access tokens are JWTs verifiable at /jwks — + // exactly what the MCP server needs. DCR lets Claude self-register; the + // unauthenticated variant is required because MCP clients register before + // they have any credentials. + oauthProvider({ loginPage: "/login", + // Required by the type; not shown because skipConsent auto-approves — for + // a personal MCP connector, signing in *is* the authorization. + consentPage: "/consent", + skipConsent: true, allowDynamicClientRegistration: true, - useJWTPlugin: true, + allowUnauthenticatedClientRegistration: true, }), ], });