fix: restore MCP OAuth registration and authorization (#3421)

* fix: align MCP OAuth provider schema and authorization flow

* test: isolate OpenAPI generation from OAuth initialization

* fix: accept auth routes without a callback query

* fix: require explicit OAuth consent and preserve signed requests

* test: verify OAuth audiences through real MCP initialization

* test(e2e): isolate OAuth token audience validation
This commit is contained in:
Amruth Pillai
2026-09-05 09:33:15 -07:00
committed by GitHub
parent bf71253ca4
commit fe9b59e111
35 changed files with 7837 additions and 144 deletions
+83
View File
@@ -250,6 +250,16 @@ export const jwks = pg.pgTable("jwks", {
export const oauthClient = pg.pgTable(
"oauth_client",
{
// Additive fields required by Better Auth 1.7 OAuth provider.
clientDiscoveryId: pg.text("client_discovery_id"),
clientCredentialsScopes: pg.text("client_credentials_scopes").array().default([]),
backchannelLogoutUri: pg.text("backchannel_logout_uri"),
backchannelLogoutSessionRequired: pg.boolean("backchannel_logout_session_required"),
applicationType: pg.text("application_type"),
jwks: pg.text("jwks"),
jwksUri: pg.text("jwks_uri"),
dpopBoundAccessTokens: pg.boolean("dpop_bound_access_tokens").default(false),
id: pg
.text("id")
.notNull()
@@ -294,6 +304,15 @@ export const oauthClient = pg.pgTable(
export const oauthRefreshToken = pg.pgTable(
"oauth_refresh_token",
{
// Additive fields required by Better Auth 1.7 OAuth provider.
authorizationCodeId: pg.text("authorization_code_id"),
resources: pg.text("resources").array(),
requestedUserInfoClaims: pg.text("requested_user_info_claims").array(),
rotatedAt: pg.timestamp("rotated_at", { withTimezone: true }),
rotationReplayResponse: pg.text("rotation_replay_response"),
rotationReplayExpiresAt: pg.timestamp("rotation_replay_expires_at", { withTimezone: true }),
confirmation: pg.jsonb("confirmation"),
id: pg
.text("id")
.notNull()
@@ -322,6 +341,13 @@ export const oauthRefreshToken = pg.pgTable(
export const oauthAccessToken = pg.pgTable(
"oauth_access_token",
{
// Additive fields required by Better Auth 1.7 OAuth provider.
authorizationCodeId: pg.text("authorization_code_id"),
resources: pg.text("resources").array(),
requestedUserInfoClaims: pg.text("requested_user_info_claims").array(),
revoked: pg.timestamp("revoked", { withTimezone: true }),
confirmation: pg.jsonb("confirmation"),
id: pg
.text("id")
.notNull()
@@ -346,6 +372,10 @@ export const oauthAccessToken = pg.pgTable(
export const oauthConsent = pg.pgTable(
"oauth_consent",
{
// Additive fields required by Better Auth 1.7 OAuth provider.
resources: pg.text("resources").array(),
requestedUserInfoClaims: pg.text("requested_user_info_claims").array(),
id: pg
.text("id")
.notNull()
@@ -366,3 +396,56 @@ export const oauthConsent = pg.pgTable(
},
(t) => [pg.index().on(t.userId, t.clientId)],
);
export const oauthResource = pg.pgTable("oauth_resource", {
id: pg
.text("id")
.notNull()
.primaryKey()
.$defaultFn(() => generateId()),
identifier: pg.text("identifier").notNull().unique(),
name: pg.text("name").notNull(),
accessTokenTtl: pg.integer("access_token_ttl"),
refreshTokenTtl: pg.integer("refresh_token_ttl"),
signingAlgorithm: pg.text("signing_algorithm"),
signingKeyId: pg.text("signing_key_id"),
allowedScopes: pg.text("allowed_scopes").array(),
customClaims: pg.jsonb("custom_claims"),
dpopBoundAccessTokensRequired: pg.boolean("dpop_bound_access_tokens_required").default(false),
disabled: pg.boolean("disabled").default(false),
createdAt: pg.timestamp("created_at", { withTimezone: true }),
updatedAt: pg.timestamp("updated_at", { withTimezone: true }),
policyVersion: pg.integer("policy_version").default(1),
metadata: pg.jsonb("metadata"),
});
export const oauthClientResource = pg.pgTable(
"oauth_client_resource",
{
id: pg
.text("id")
.notNull()
.primaryKey()
.$defaultFn(() => generateId()),
clientId: pg
.text("client_id")
.notNull()
.references(() => oauthClient.clientId, { onDelete: "cascade" }),
resourceId: pg
.text("resource_id")
.notNull()
.references(() => oauthResource.identifier, { onDelete: "cascade" }),
metadata: pg.jsonb("metadata"),
createdAt: pg.timestamp("created_at", { withTimezone: true }),
},
(t) => [pg.index().on(t.clientId), pg.index().on(t.resourceId), pg.uniqueIndex().on(t.clientId, t.resourceId)],
);
export const oauthClientAssertion = pg.pgTable("oauth_client_assertion", {
id: pg
.text("id")
.notNull()
.primaryKey()
.$defaultFn(() => generateId()),
expiresAt: pg.timestamp("expires_at", { withTimezone: true }).notNull(),
});