[GH-ISSUE #5468] OIDC Plugin trustedClients cannot be used due to foreign key constraints #27582

Closed
opened 2026-04-17 18:40:14 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @rbayliss on GitHub (Oct 21, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5468

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create a backend using oidc plugin, using trustedClients where one of your trusted clients requires a consent screen.
  2. Attempt to login using one of the trusted clients.
  3. When authClient.oauth2.consent is called, observe a database error: "SERVER_ERROR: [Error: FOREIGN KEY constraint failed]"
  4. The same happens when the oauth2/token endpoint is called.

Current vs. Expected behavior

Current behavior:
Trusted clients can't be used for consent, or return access tokens, due to the fact that they're not in the oauthApplication table, and the oauthAccessToken and oauthConsent tables use a foreign key to reference oauthApplication.

Expected behavior:
Trusted clients can be used for consent and return login tokens.

What version of Better Auth are you using?

1.3.28

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Aug 11 21:15:09 PDT 2025; root:xnu-11417.140.69.701.11~1/RELEASE_ARM64_T6041",
    "release": "24.6.0",
    "cpuCount": 14,
    "cpuModel": "Apple M4 Pro",
    "totalMemory": "48.00 GB",
    "freeMemory": "4.83 GB"
  },
  "node": {
    "version": "v24.9.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.0"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "15.5.6"
    },
    {
      "name": "react",
      "version": "19.1.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.3.28",
    "config": {
      "database": {
        "isOpen": true,
        "isTransaction": false
      },
      "logger": {
        "level": "debug"
      },
      "plugins": [
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "jwt",
          "config": {
            "id": "jwt",
            "endpoints": {},
            "hooks": {
              "after": [
                {}
              ]
            },
            "schema": {
              "jwks": {
                "fields": {
                  "publicKey": {
                    "type": "string",
                    "required": true
                  },
                  "privateKey": {
                    "type": "string",
                    "required": true
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  }
                }
              }
            }
          }
        },
        {
          "name": "oidc",
          "config": {
            "id": "oidc",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "schema": {
              "oauthApplication": {
                "modelName": "oauthApplication",
                "fields": {
                  "name": {
                    "type": "string"
                  },
                  "icon": {
                    "type": "string",
                    "required": false
                  },
                  "metadata": {
                    "type": "string",
                    "required": false
                  },
                  "clientId": {
                    "type": "string",
                    "unique": true
                  },
                  "clientSecret": {
                    "type": "string",
                    "required": false
                  },
                  "redirectURLs": {
                    "type": "string"
                  },
                  "type": {
                    "type": "string"
                  },
                  "disabled": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false
                  },
                  "userId": {
                    "type": "string",
                    "required": false,
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    }
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  }
                }
              },
              "oauthAccessToken": {
                "modelName": "oauthAccessToken",
                "fields": {
                  "accessToken": {
                    "type": "string",
                    "unique": true
                  },
                  "refreshToken": {
                    "type": "string",
                    "unique": true
                  },
                  "accessTokenExpiresAt": {
                    "type": "date"
                  },
                  "refreshTokenExpiresAt": {
                    "type": "date"
                  },
                  "clientId": {
                    "type": "string",
                    "references": {
                      "model": "oauthApplication",
                      "field": "clientId",
                      "onDelete": "cascade"
                    }
                  },
                  "userId": {
                    "type": "string",
                    "required": false,
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    }
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  }
                }
              },
              "oauthConsent": {
                "modelName": "oauthConsent",
                "fields": {
                  "clientId": {
                    "type": "string",
                    "references": {
                      "model": "oauthApplication",
                      "field": "clientId",
                      "onDelete": "cascade"
                    }
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    }
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  },
                  "consentGiven": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      ],
      "socialProviders": {
        "cognito": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "domain": "[REDACTED]",
          "region": "us-east-1",
          "userPoolId": "[REDACTED]"
        }
      },
      "advanced": {
        "defaultCookieAttributes": {
          "secure": false
        }
      }
    }
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { DatabaseSync } from "node:sqlite";
import { nextCookies } from "better-auth/next-js";
import { jwt } from "better-auth/plugins";
import {oidcProvider, Client} from "better-auth/plugins/oidc-provider";
import creds from "@/creds.json";

const clients: Client[] = [
  {
    clientId: "foo",
    clientSecret: "bar",
    name: "Test App",
    type: "web",
    redirectURLs: ["REDACTED"],
    disabled: false,
    skipConsent: false,
    metadata: {internal: true},
  }
]

export const auth = betterAuth({
  database: new DatabaseSync("./sqlite.db"),
  logger: {
    level: "debug",
  },
  plugins: [
    nextCookies(),
    jwt(),
    oidcProvider({
      loginPage: "/auth/sign-in",
      consentPage: "/auth/consent",
      useJWTPlugin: true,
      allowDynamicClientRegistration: false,
      trustedClients: clients,
      metadata: {
        issuer: 'http://localhost:4000/api/auth'
      },
    })
  ],
  socialProviders: {
    cognito: {
      clientId: creds.client_id,
      clientSecret: creds.client_secret,
      domain: creds.domain,
      region: creds.region,
      userPoolId: creds.user_pool_id,
    }
  },
  advanced: {
    defaultCookieAttributes: {
      secure: false,
    }
  },
});

Additional context

No response

Originally created by @rbayliss on GitHub (Oct 21, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5468 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create a backend using oidc plugin, using `trustedClients` where one of your trusted clients requires a consent screen. 2. Attempt to login using one of the trusted clients. 3. When `authClient.oauth2.consent` is called, observe a database error: "SERVER_ERROR: [Error: FOREIGN KEY constraint failed]" 4. The same happens when the oauth2/token endpoint is called. ### Current vs. Expected behavior Current behavior: Trusted clients can't be used for consent, or return access tokens, due to the fact that they're not in the `oauthApplication` table, and the `oauthAccessToken` and `oauthConsent` tables use a foreign key to reference `oauthApplication`. Expected behavior: Trusted clients can be used for consent and return login tokens. ### What version of Better Auth are you using? 1.3.28 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Aug 11 21:15:09 PDT 2025; root:xnu-11417.140.69.701.11~1/RELEASE_ARM64_T6041", "release": "24.6.0", "cpuCount": 14, "cpuModel": "Apple M4 Pro", "totalMemory": "48.00 GB", "freeMemory": "4.83 GB" }, "node": { "version": "v24.9.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.0" }, "frameworks": [ { "name": "next", "version": "15.5.6" }, { "name": "react", "version": "19.1.0" } ], "databases": null, "betterAuth": { "version": "^1.3.28", "config": { "database": { "isOpen": true, "isTransaction": false }, "logger": { "level": "debug" }, "plugins": [ { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } }, { "name": "jwt", "config": { "id": "jwt", "endpoints": {}, "hooks": { "after": [ {} ] }, "schema": { "jwks": { "fields": { "publicKey": { "type": "string", "required": true }, "privateKey": { "type": "string", "required": true }, "createdAt": { "type": "date", "required": true } } } } } }, { "name": "oidc", "config": { "id": "oidc", "hooks": { "after": [ {} ] }, "endpoints": {}, "schema": { "oauthApplication": { "modelName": "oauthApplication", "fields": { "name": { "type": "string" }, "icon": { "type": "string", "required": false }, "metadata": { "type": "string", "required": false }, "clientId": { "type": "string", "unique": true }, "clientSecret": { "type": "string", "required": false }, "redirectURLs": { "type": "string" }, "type": { "type": "string" }, "disabled": { "type": "boolean", "required": false, "defaultValue": false }, "userId": { "type": "string", "required": false, "references": { "model": "user", "field": "id", "onDelete": "cascade" } }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" } } }, "oauthAccessToken": { "modelName": "oauthAccessToken", "fields": { "accessToken": { "type": "string", "unique": true }, "refreshToken": { "type": "string", "unique": true }, "accessTokenExpiresAt": { "type": "date" }, "refreshTokenExpiresAt": { "type": "date" }, "clientId": { "type": "string", "references": { "model": "oauthApplication", "field": "clientId", "onDelete": "cascade" } }, "userId": { "type": "string", "required": false, "references": { "model": "user", "field": "id", "onDelete": "cascade" } }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" } } }, "oauthConsent": { "modelName": "oauthConsent", "fields": { "clientId": { "type": "string", "references": { "model": "oauthApplication", "field": "clientId", "onDelete": "cascade" } }, "userId": { "type": "string", "references": { "model": "user", "field": "id", "onDelete": "cascade" } }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" }, "consentGiven": { "type": "boolean" } } } } } } ], "socialProviders": { "cognito": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "domain": "[REDACTED]", "region": "us-east-1", "userPoolId": "[REDACTED]" } }, "advanced": { "defaultCookieAttributes": { "secure": false } } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { DatabaseSync } from "node:sqlite"; import { nextCookies } from "better-auth/next-js"; import { jwt } from "better-auth/plugins"; import {oidcProvider, Client} from "better-auth/plugins/oidc-provider"; import creds from "@/creds.json"; const clients: Client[] = [ { clientId: "foo", clientSecret: "bar", name: "Test App", type: "web", redirectURLs: ["REDACTED"], disabled: false, skipConsent: false, metadata: {internal: true}, } ] export const auth = betterAuth({ database: new DatabaseSync("./sqlite.db"), logger: { level: "debug", }, plugins: [ nextCookies(), jwt(), oidcProvider({ loginPage: "/auth/sign-in", consentPage: "/auth/consent", useJWTPlugin: true, allowDynamicClientRegistration: false, trustedClients: clients, metadata: { issuer: 'http://localhost:4000/api/auth' }, }) ], socialProviders: { cognito: { clientId: creds.client_id, clientSecret: creds.client_secret, domain: creds.domain, region: creds.region, userPoolId: creds.user_pool_id, } }, advanced: { defaultCookieAttributes: { secure: false, } }, }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-17 18:40:14 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 21, 2025):

Hi @rbayliss! I'm Dosu and I’m helping the better-auth team.

This is a known limitation: trustedClients configured in the OIDC plugin are not automatically inserted into the oauthApplication table, but the oauthAccessToken and oauthConsent tables require a valid clientId foreign key reference to oauthApplication. That's why you see a foreign key constraint error when using trustedClients for consent or token flows (details, code reference).

To work around this, you need to manually insert your trusted clients into the oauthApplication table with matching fields (clientId, clientSecret, name, redirectURLs, type, etc). You can do this with a direct SQL insert, a Prisma create, or by enabling dynamic client registration and using the /oauth2/register endpoint (example and discussion). Once the client exists in the table, consent and token flows will work as expected.

This gap between the docs and implementation is known and being tracked (discussion).

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3429679676 --> @dosubot[bot] commented on GitHub (Oct 21, 2025): <!-- Greeting --> Hi @rbayliss! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known limitation: trustedClients configured in the OIDC plugin are not automatically inserted into the `oauthApplication` table, but the `oauthAccessToken` and `oauthConsent` tables require a valid `clientId` foreign key reference to `oauthApplication`. That's why you see a foreign key constraint error when using trustedClients for consent or token flows ([details](https://github.com/better-auth/better-auth/issues/4749), [code reference](https://github.com/better-auth/better-auth/blob/fa6ee9d68214c6a51e7253b53f957407b116b0c4/packages/better-auth/src/plugins/oidc-provider/index.ts)). To work around this, you need to manually insert your trusted clients into the `oauthApplication` table with matching fields (`clientId`, `clientSecret`, `name`, `redirectURLs`, `type`, etc). You can do this with a direct SQL insert, a Prisma create, or by enabling dynamic client registration and using the `/oauth2/register` endpoint ([example and discussion](https://github.com/better-auth/better-auth/issues/5040)). Once the client exists in the table, consent and token flows will work as expected. This gap between the docs and implementation is known and being tracked ([discussion](https://github.com/better-auth/better-auth/issues/4749)). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/22470be4-5bbe-4ccc-be0d-021fd9075b5f?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5468)
Author
Owner

@rbayliss commented on GitHub (Oct 22, 2025):

Ok, fair! Thanks!

<!-- gh-comment-id:3433498475 --> @rbayliss commented on GitHub (Oct 22, 2025): Ok, fair! Thanks!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27582