[Bug]: Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths #2382

Closed
opened 2026-03-13 09:48:34 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @bennajah on GitHub (Nov 24, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. install mcp and oidcProvider plusins
  2. run npx @better-auth/cli generate
  3. see error

Current vs. Expected behavior

[Better Auth]: Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods:
  - "/oauth2/consent" [POST] used by plugins: mcp, oidc

To resolve this, you can:
        1. Use only one of the conflicting plugins
        2. Configure the plugins to use different paths (if supported)
        3. Ensure plugins use different HTTP methods for the same path

What version of Better Auth are you using?

1.4.1

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26200",
    "cpuCount": 8,
    "cpuModel": "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz",
    "totalMemory": "11.96 GB",
    "freeMemory": "3.99 GB"
  },
  "node": {
    "version": "v24.3.0",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.3"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.0.3"
    },
    {
      "name": "react",
      "version": "^19.2.0"
    }
  ],
  "databases": [
    {
      "name": "drizzle",
      "version": "^0.44.7"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.4.1",
    "config": {
      "appName": "my-app",
      "emailAndPassword": {
        "enabled": true,
        "autoSignIn": true,
        "requireEmailVerification": true
      },
      "emailVerification": {
        "sendOnSignIn": true,
        "sendOnSignUp": true,
        "autoSignInAfterVerification": true
      },
      "socialProviders": {
        "google": {
          "enabled": true,
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        },
        "facebook": {
          "enabled": true,
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "trustedProviders": ["google", "facebook", "email-password"]
        }
      },
      "plugins": [
        {
          "name": "two-factor",
          "config": {
            "id": "two-factor",
            "endpoints": {},
            "hooks": {
              "after": [{}]
            },
            "schema": {
              "user": {
                "fields": {
                  "twoFactorEnabled": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false,
                    "input": false
                  }
                }
              },
              "twoFactor": {
                "fields": {
                  "secret": {
                    "type": "string",
                    "required": true,
                    "returned": false,
                    "index": true
                  },
                  "backupCodes": {
                    "type": "string",
                    "required": true,
                    "returned": false
                  },
                  "userId": {
                    "type": "string",
                    "required": true,
                    "returned": false,
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "index": true
                  }
                }
              }
            },
            "rateLimit": [
              {
                "window": 10,
                "max": 3
              }
            ],
            "$ERROR_CODES": {
              "OTP_NOT_ENABLED": "OTP not enabled",
              "OTP_HAS_EXPIRED": "OTP has expired",
              "TOTP_NOT_ENABLED": "TOTP not enabled",
              "TWO_FACTOR_NOT_ENABLED": "Two factor isn't enabled",
              "BACKUP_CODES_NOT_ENABLED": "Backup codes aren't enabled",
              "INVALID_BACKUP_CODE": "Invalid backup code",
              "INVALID_CODE": "Invalid code",
              "TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE": "Too many attempts. Please request a new code.",
              "INVALID_TWO_FACTOR_COOKIE": "Invalid two factor cookie"
            }
          }
        },
        {
          "name": "username",
          "config": {
            "id": "username",
            "endpoints": {},
            "schema": {
              "user": {
                "fields": {
                  "username": {
                    "type": "string",
                    "required": false,
                    "sortable": true,
                    "unique": true,
                    "returned": true,
                    "transform": {}
                  },
                  "displayUsername": {
                    "type": "string",
                    "required": false,
                    "transform": {}
                  }
                }
              }
            },
            "hooks": {
              "before": [{}, {}]
            },
            "$ERROR_CODES": {
              "INVALID_USERNAME_OR_PASSWORD": "[REDACTED]",
              "EMAIL_NOT_VERIFIED": "Email not verified",
              "UNEXPECTED_ERROR": "Unexpected error",
              "USERNAME_IS_ALREADY_TAKEN": "Username is already taken. Please try another.",
              "USERNAME_TOO_SHORT": "Username is too short",
              "USERNAME_TOO_LONG": "Username is too long",
              "INVALID_USERNAME": "Username is invalid",
              "INVALID_DISPLAY_USERNAME": "Display username is invalid"
            }
          }
        },
        {
          "name": "anonymous",
          "config": {
            "id": "anonymous",
            "endpoints": {},
            "hooks": {
              "after": [{}]
            },
            "schema": {
              "user": {
                "fields": {
                  "isAnonymous": {
                    "type": "boolean",
                    "required": false,
                    "input": false,
                    "defaultValue": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "INVALID_EMAIL_FORMAT": "Email was not generated in a valid format",
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "COULD_NOT_CREATE_SESSION": "Could not create session",
              "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": "Anonymous users cannot sign in again anonymously"
            }
          }
        },
        {
          "name": "phone-number",
          "config": {
            "id": "phone-number",
            "hooks": {
              "before": [{}]
            },
            "endpoints": {},
            "schema": {
              "user": {
                "fields": {
                  "phoneNumber": {
                    "type": "string",
                    "required": false,
                    "unique": true,
                    "sortable": true,
                    "returned": true
                  },
                  "phoneNumberVerified": {
                    "type": "boolean",
                    "required": false,
                    "returned": true,
                    "input": false
                  }
                }
              }
            },
            "rateLimit": [
              {
                "window": 60000,
                "max": 10
              }
            ],
            "$ERROR_CODES": {
              "INVALID_PHONE_NUMBER": "Invalid phone number",
              "PHONE_NUMBER_EXIST": "Phone number already exists",
              "PHONE_NUMBER_NOT_EXIST": "phone number isn't registered",
              "INVALID_PHONE_NUMBER_OR_PASSWORD": "[REDACTED]",
              "UNEXPECTED_ERROR": "Unexpected error",
              "OTP_NOT_FOUND": "OTP not found",
              "OTP_EXPIRED": "OTP expired",
              "INVALID_OTP": "Invalid OTP",
              "PHONE_NUMBER_NOT_VERIFIED": "Phone number not verified",
              "PHONE_NUMBER_CANNOT_BE_UPDATED": "Phone number cannot be updated",
              "SEND_OTP_NOT_IMPLEMENTED": "sendOTP not implemented",
              "TOO_MANY_ATTEMPTS": "Too many attempts"
            }
          }
        },
        {
          "name": "magic-link",
          "config": {
            "id": "magic-link",
            "endpoints": {},
            "rateLimit": [
              {
                "window": 60,
                "max": 5
              }
            ]
          }
        },
        {
          "name": "email-otp",
          "config": {
            "id": "email-otp",
            "endpoints": {},
            "hooks": {
              "after": [{}]
            },
            "$ERROR_CODES": {
              "OTP_EXPIRED": "OTP expired",
              "INVALID_OTP": "Invalid OTP",
              "TOO_MANY_ATTEMPTS": "Too many attempts"
            },
            "rateLimit": [
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              },
              {
                "window": 60,
                "max": 3
              }
            ]
          }
        },
        {
          "name": "passkey",
          "config": {
            "id": "passkey",
            "endpoints": {},
            "schema": {
              "passkey": {
                "fields": {
                  "name": {
                    "type": "string",
                    "required": false
                  },
                  "publicKey": {
                    "type": "string",
                    "required": true
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "required": true,
                    "index": true
                  },
                  "credentialID": {
                    "type": "string",
                    "required": true,
                    "index": true
                  },
                  "counter": {
                    "type": "number",
                    "required": true
                  },
                  "deviceType": {
                    "type": "string",
                    "required": true
                  },
                  "backedUp": {
                    "type": "boolean",
                    "required": true
                  },
                  "transports": {
                    "type": "string",
                    "required": false
                  },
                  "createdAt": {
                    "type": "date",
                    "required": false
                  },
                  "aaguid": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "CHALLENGE_NOT_FOUND": "Challenge not found",
              "YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY": "You are not allowed to register this passkey",
              "FAILED_TO_VERIFY_REGISTRATION": "Failed to verify registration",
              "PASSKEY_NOT_FOUND": "Passkey not found",
              "AUTHENTICATION_FAILED": "Authentication failed",
              "UNABLE_TO_CREATE_SESSION": "Unable to create session",
              "FAILED_TO_UPDATE_PASSKEY": "Failed to update passkey"
            }
          }
        },
        {
          "name": "generic-oauth",
          "config": {
            "id": "generic-oauth",
            "endpoints": {},
            "$ERROR_CODES": {
              "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration",
              "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.",
              "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider",
              "PROVIDER_ID_REQUIRED": "Provider ID is required",
              "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.",
              "SESSION_REQUIRED": "Session is required"
            }
          }
        },
        {
          "name": "one-tap",
          "config": {
            "id": "one-tap",
            "endpoints": {}
          }
        },
        {
          "name": "siwe",
          "config": {
            "id": "siwe",
            "schema": {
              "walletAddress": {
                "fields": {
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "required": true,
                    "index": true
                  },
                  "address": {
                    "type": "string",
                    "required": true
                  },
                  "chainId": {
                    "type": "number",
                    "required": true
                  },
                  "isPrimary": {
                    "type": "boolean",
                    "defaultValue": false
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  }
                }
              }
            },
            "endpoints": {}
          }
        },
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [{}]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        },
        {
          "name": "api-key",
          "config": {
            "id": "api-key",
            "$ERROR_CODES": {
              "INVALID_METADATA_TYPE": "metadata must be an object or undefined",
              "REFILL_AMOUNT_AND_INTERVAL_REQUIRED": "refillAmount is required when refillInterval is provided",
              "REFILL_INTERVAL_AND_AMOUNT_REQUIRED": "refillInterval is required when refillAmount is provided",
              "USER_BANNED": "User is banned",
              "UNAUTHORIZED_SESSION": "Unauthorized or invalid session",
              "KEY_NOT_FOUND": "API Key not found",
              "KEY_DISABLED": "API Key is disabled",
              "KEY_EXPIRED": "API Key has expired",
              "USAGE_EXCEEDED": "API Key has reached its usage limit",
              "KEY_NOT_RECOVERABLE": "API Key is not recoverable",
              "EXPIRES_IN_IS_TOO_SMALL": "The expiresIn is smaller than the predefined minimum value.",
              "EXPIRES_IN_IS_TOO_LARGE": "The expiresIn is larger than the predefined maximum value.",
              "INVALID_REMAINING": "The remaining count is either too large or too small.",
              "INVALID_PREFIX_LENGTH": "The prefix length is either too large or too small.",
              "INVALID_NAME_LENGTH": "The name length is either too large or too small.",
              "METADATA_DISABLED": "Metadata is disabled.",
              "RATE_LIMIT_EXCEEDED": "Rate limit exceeded.",
              "NO_VALUES_TO_UPDATE": "No values to update.",
              "KEY_DISABLED_EXPIRATION": "Custom key expiration values are disabled.",
              "INVALID_API_KEY": "Invalid API key.",
              "INVALID_USER_ID_FROM_API_KEY": "The user id from the API key is invalid.",
              "INVALID_API_KEY_GETTER_RETURN_TYPE": "API Key getter returned an invalid key type. Expected string.",
              "SERVER_ONLY_PROPERTY": "The property you're trying to set can only be set from the server auth instance only.",
              "FAILED_TO_UPDATE_API_KEY": "Failed to update API key",
              "NAME_REQUIRED": "API Key name is required."
            },
            "hooks": {
              "before": [{}]
            },
            "endpoints": {},
            "schema": {
              "apikey": {
                "fields": {
                  "name": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "start": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "prefix": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "key": {
                    "type": "string",
                    "required": true,
                    "input": false,
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    },
                    "required": true,
                    "input": false,
                    "index": true
                  },
                  "refillInterval": {
                    "type": "number",
                    "required": false,
                    "input": false
                  },
                  "refillAmount": {
                    "type": "number",
                    "required": false,
                    "input": false
                  },
                  "lastRefillAt": {
                    "type": "date",
                    "required": false,
                    "input": false
                  },
                  "enabled": {
                    "type": "boolean",
                    "required": false,
                    "input": false,
                    "defaultValue": true
                  },
                  "rateLimitEnabled": {
                    "type": "boolean",
                    "required": false,
                    "input": false,
                    "defaultValue": true
                  },
                  "rateLimitTimeWindow": {
                    "type": "number",
                    "required": false,
                    "input": false,
                    "defaultValue": 86400000
                  },
                  "rateLimitMax": {
                    "type": "number",
                    "required": false,
                    "input": false,
                    "defaultValue": 10
                  },
                  "requestCount": {
                    "type": "number",
                    "required": false,
                    "input": false,
                    "defaultValue": 0
                  },
                  "remaining": {
                    "type": "number",
                    "required": false,
                    "input": false
                  },
                  "lastRequest": {
                    "type": "date",
                    "required": false,
                    "input": false
                  },
                  "expiresAt": {
                    "type": "date",
                    "required": false,
                    "input": false
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true,
                    "input": false
                  },
                  "updatedAt": {
                    "type": "date",
                    "required": true,
                    "input": false
                  },
                  "permissions": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "metadata": {
                    "type": "string",
                    "required": false,
                    "input": true,
                    "transform": {}
                  }
                }
              }
            }
          }
        },
        {
          "name": "mcp",
          "config": {
            "id": "mcp",
            "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"
                    },
                    "index": true
                  },
                  "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"
                    },
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "required": false,
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  }
                }
              },
              "oauthConsent": {
                "modelName": "oauthConsent",
                "fields": {
                  "clientId": {
                    "type": "string",
                    "references": {
                      "model": "oauthApplication",
                      "field": "clientId",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  },
                  "consentGiven": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        {
          "name": "organization",
          "config": {
            "id": "organization",
            "endpoints": {},
            "schema": {
              "organization": {
                "fields": {
                  "name": {
                    "type": "string",
                    "required": true,
                    "sortable": true
                  },
                  "slug": {
                    "type": "string",
                    "required": true,
                    "unique": true,
                    "sortable": true
                  },
                  "logo": {
                    "type": "string",
                    "required": false
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  },
                  "metadata": {
                    "type": "string",
                    "required": false
                  }
                }
              },
              "member": {
                "fields": {
                  "organizationId": {
                    "type": "string",
                    "required": true,
                    "references": {
                      "model": "organization",
                      "field": "id"
                    },
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "required": true,
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "index": true
                  },
                  "role": {
                    "type": "string",
                    "required": true,
                    "sortable": true,
                    "defaultValue": "member"
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  }
                }
              },
              "invitation": {
                "fields": {
                  "organizationId": {
                    "type": "string",
                    "required": true,
                    "references": {
                      "model": "organization",
                      "field": "id"
                    },
                    "index": true
                  },
                  "email": {
                    "type": "string",
                    "required": true,
                    "sortable": true,
                    "index": true
                  },
                  "role": {
                    "type": "string",
                    "required": false,
                    "sortable": true
                  },
                  "status": {
                    "type": "string",
                    "required": true,
                    "sortable": true,
                    "defaultValue": "pending"
                  },
                  "expiresAt": {
                    "type": "date",
                    "required": true
                  },
                  "createdAt": {
                    "type": "date",
                    "required": true
                  },
                  "inviterId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "required": true
                  }
                }
              },
              "session": {
                "fields": {
                  "activeOrganizationId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "$Infer": {
              "Organization": {},
              "Invitation": {},
              "Member": {},
              "Team": {},
              "TeamMember": {},
              "ActiveOrganization": {}
            },
            "$ERROR_CODES": {
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION": "You are not allowed to create a new organization",
              "YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS": "You have reached the maximum number of organizations",
              "ORGANIZATION_ALREADY_EXISTS": "Organization already exists",
              "ORGANIZATION_SLUG_ALREADY_TAKEN": "Organization slug already taken",
              "ORGANIZATION_NOT_FOUND": "Organization not found",
              "USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION": "User is not a member of the organization",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION": "You are not allowed to update this organization",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION": "You are not allowed to delete this organization",
              "NO_ACTIVE_ORGANIZATION": "No active organization",
              "USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION": "User is already a member of this organization",
              "MEMBER_NOT_FOUND": "Member not found",
              "ROLE_NOT_FOUND": "Role not found",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM": "You are not allowed to create a new team",
              "TEAM_ALREADY_EXISTS": "Team already exists",
              "TEAM_NOT_FOUND": "Team not found",
              "YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER": "You cannot leave the organization as the only owner",
              "YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER": "You cannot leave the organization without an owner",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER": "You are not allowed to delete this member",
              "YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION": "You are not allowed to invite users to this organization",
              "USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION": "User is already invited to this organization",
              "INVITATION_NOT_FOUND": "Invitation not found",
              "YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION": "You are not the recipient of the invitation",
              "EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION": "Email verification required before accepting or rejecting invitation",
              "YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION": "You are not allowed to cancel this invitation",
              "INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION": "Inviter is no longer a member of the organization",
              "YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE": "You are not allowed to invite a user with this role",
              "FAILED_TO_RETRIEVE_INVITATION": "Failed to retrieve invitation",
              "YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS": "You have reached the maximum number of teams",
              "UNABLE_TO_REMOVE_LAST_TEAM": "Unable to remove last team",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER": "You are not allowed to update this member",
              "ORGANIZATION_MEMBERSHIP_LIMIT_REACHED": "Organization membership limit reached",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION": "You are not allowed to create teams in this organization",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION": "You are not allowed to delete teams in this organization",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM": "You are not allowed to update this team",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM": "You are not allowed to delete this team",
              "INVITATION_LIMIT_REACHED": "Invitation limit reached",
              "TEAM_MEMBER_LIMIT_REACHED": "Team member limit reached",
              "USER_IS_NOT_A_MEMBER_OF_THE_TEAM": "User is not a member of the team",
              "YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM": "You are not allowed to list the members of this team",
              "YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM": "You do not have an active team",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER": "You are not allowed to create a new member",
              "YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER": "You are not allowed to remove a team member",
              "YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION": "You are not allowed to access this organization as an owner",
              "YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION": "You are not a member of this organization",
              "MISSING_AC_INSTANCE": "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information",
              "YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE": "You must be in an organization to create a role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE": "You are not allowed to create a role",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE": "You are not allowed to update a role",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE": "You are not allowed to delete a role",
              "YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE": "You are not allowed to read a role",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE": "You are not allowed to list a role",
              "YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE": "You are not allowed to get a role",
              "TOO_MANY_ROLES": "This organization has too many roles",
              "INVALID_RESOURCE": "The provided permission includes an invalid resource",
              "ROLE_NAME_IS_ALREADY_TAKEN": "That role name is already taken",
              "CANNOT_DELETE_A_PRE_DEFINED_ROLE": "Cannot delete a pre-defined role"
            }
          }
        },
        {
          "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"
                    },
                    "index": true
                  },
                  "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"
                    },
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "required": false,
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  }
                }
              },
              "oauthConsent": {
                "modelName": "oauthConsent",
                "fields": {
                  "clientId": {
                    "type": "string",
                    "references": {
                      "model": "oauthApplication",
                      "field": "clientId",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id",
                      "onDelete": "cascade"
                    },
                    "index": true
                  },
                  "scopes": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "date"
                  },
                  "updatedAt": {
                    "type": "date"
                  },
                  "consentGiven": {
                    "type": "boolean"
                  }
                }
              }
            },
            "options": {
              "codeExpiresIn": 600,
              "defaultScope": "openid",
              "accessTokenExpiresIn": 3600,
              "refreshTokenExpiresIn": 604800,
              "allowPlainCodeChallengeMethod": true,
              "storeClientSecret": "[REDACTED]",
              "loginPage": "/sign-in",
              "scopes": ["openid", "profile", "email", "offline_access"]
            }
          }
        },
        {
          "name": "sso",
          "config": {
            "id": "sso",
            "endpoints": {},
            "schema": {
              "ssoProvider": {
                "modelName": "ssoProvider",
                "fields": {
                  "issuer": {
                    "type": "string",
                    "required": true,
                    "fieldName": "issuer"
                  },
                  "oidcConfig": {
                    "type": "string",
                    "required": false,
                    "fieldName": "oidcConfig"
                  },
                  "samlConfig": {
                    "type": "string",
                    "required": false,
                    "fieldName": "samlConfig"
                  },
                  "userId": {
                    "type": "string",
                    "references": {
                      "model": "user",
                      "field": "id"
                    },
                    "fieldName": "userId"
                  },
                  "providerId": {
                    "type": "string",
                    "required": true,
                    "unique": true,
                    "fieldName": "providerId"
                  },
                  "organizationId": {
                    "type": "string",
                    "required": false,
                    "fieldName": "organizationId"
                  },
                  "domain": {
                    "type": "string",
                    "required": true,
                    "fieldName": "domain"
                  }
                }
              }
            }
          }
        },
        {
          "name": "scim",
          "config": {
            "id": "scim",
            "endpoints": {},
            "schema": {
              "scimProvider": {
                "fields": {
                  "providerId": {
                    "type": "string",
                    "required": true,
                    "unique": true
                  },
                  "scimToken": {
                    "type": "string",
                    "required": true,
                    "unique": true
                  },
                  "organizationId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        },
        {
          "name": "bearer",
          "config": {
            "id": "bearer",
            "hooks": {
              "before": [{}],
              "after": [{}]
            }
          }
        },
        {
          "name": "device-authorization",
          "config": {
            "id": "device-authorization",
            "schema": {
              "deviceCode": {
                "fields": {
                  "deviceCode": {
                    "type": "string",
                    "required": true
                  },
                  "userCode": {
                    "type": "string",
                    "required": true
                  },
                  "userId": {
                    "type": "string",
                    "required": false
                  },
                  "expiresAt": {
                    "type": "date",
                    "required": true
                  },
                  "status": {
                    "type": "string",
                    "required": true
                  },
                  "lastPolledAt": {
                    "type": "date",
                    "required": false
                  },
                  "pollingInterval": {
                    "type": "number",
                    "required": false
                  },
                  "clientId": {
                    "type": "string",
                    "required": false
                  },
                  "scope": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "INVALID_DEVICE_CODE": "Invalid device code",
              "EXPIRED_DEVICE_CODE": "Device code has expired",
              "EXPIRED_USER_CODE": "User code has expired",
              "AUTHORIZATION_PENDING": "Authorization pending",
              "ACCESS_DENIED": "Access denied",
              "INVALID_USER_CODE": "Invalid user code",
              "DEVICE_CODE_ALREADY_PROCESSED": "Device code already processed",
              "POLLING_TOO_FREQUENTLY": "Polling too frequently",
              "USER_NOT_FOUND": "User not found",
              "FAILED_TO_CREATE_SESSION": "Failed to create session",
              "INVALID_DEVICE_CODE_STATUS": "Invalid device code status",
              "AUTHENTICATION_REQUIRED": "Authentication required"
            }
          }
        },
        {
          "name": "captcha",
          "config": {
            "id": "captcha"
          }
        },
        {
          "name": "haveIBeenPwned",
          "config": {
            "id": "haveIBeenPwned",
            "$ERROR_CODES": {
              "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password."
            }
          }
        },
        {
          "name": "last-login-method",
          "config": {
            "id": "last-login-method",
            "hooks": {
              "after": [{}]
            },
            "schema": {
              "user": {
                "fields": {
                  "lastLoginMethod": {
                    "type": "string",
                    "input": false,
                    "required": false,
                    "fieldName": "lastLoginMethod"
                  }
                }
              }
            }
          }
        },
        {
          "name": "multi-session",
          "config": {
            "id": "multi-session",
            "endpoints": {},
            "hooks": {
              "after": [{}, {}]
            },
            "$ERROR_CODES": {
              "INVALID_SESSION_TOKEN": "[REDACTED]"
            }
          }
        },
        {
          "name": "oauth-proxy",
          "config": {
            "id": "oauth-proxy",
            "endpoints": {},
            "hooks": {
              "before": [{}, {}, {}],
              "after": [{}, {}, {}]
            }
          }
        },
        {
          "name": "one-time-token",
          "config": {
            "id": "one-time-token",
            "endpoints": {}
          }
        },
        {
          "name": "open-api",
          "config": {
            "id": "open-api",
            "endpoints": {}
          }
        },
        {
          "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
                  },
                  "expiresAt": {
                    "type": "date",
                    "required": false
                  }
                }
              }
            }
          }
        },
        {
          "name": "stripe",
          "config": {
            "id": "stripe",
            "endpoints": {},
            "schema": {
              "subscription": {
                "fields": {
                  "plan": {
                    "type": "string",
                    "required": true
                  },
                  "referenceId": {
                    "type": "string",
                    "required": true
                  },
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  },
                  "stripeSubscriptionId": {
                    "type": "string",
                    "required": false
                  },
                  "status": {
                    "type": "string",
                    "defaultValue": "incomplete"
                  },
                  "periodStart": {
                    "type": "date",
                    "required": false
                  },
                  "periodEnd": {
                    "type": "date",
                    "required": false
                  },
                  "trialStart": {
                    "type": "date",
                    "required": false
                  },
                  "trialEnd": {
                    "type": "date",
                    "required": false
                  },
                  "cancelAtPeriodEnd": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false
                  },
                  "seats": {
                    "type": "number",
                    "required": false
                  }
                }
              },
              "user": {
                "fields": {
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "SUBSCRIPTION_NOT_FOUND": "Subscription not found",
              "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found",
              "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan",
              "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer",
              "FAILED_TO_FETCH_PLANS": "Failed to fetch plans",
              "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan",
              "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active",
              "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation"
            }
          }
        },
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [{}]
            }
          }
        }
      ],
      "experimental": {
        "joins": true
      }
    }
  }
}

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

Backend, Client

Auth config (if applicable)

import { passkey } from "@better-auth/passkey";
import { scim } from "@better-auth/scim";
import { sso } from "@better-auth/sso";
import { stripe } from "@better-auth/stripe";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { generateRandomString } from "better-auth/crypto";
import { nextCookies } from "better-auth/next-js";
import {
  admin,
  anonymous,
  apiKey,
  bearer,
  captcha,
  deviceAuthorization,
  emailOTP,
  genericOAuth,
  haveIBeenPwned,
  jwt,
  lastLoginMethod,
  magicLink,
  mcp,
  multiSession,
  oAuthProxy,
  oidcProvider,
  oneTap,
  oneTimeToken,
  openAPI,
  organization,
  phoneNumber,
  siwe,
  twoFactor,
  username,
} from "better-auth/plugins";
import { createPublicClient, http, verifyMessage } from "viem";
import { mainnet } from "viem/chains";
import { db } from "@/db";
// biome-ignore lint/performance/noNamespaceImport: ""
import * as schema from "@/db/schema";
import { stripe as stripeClient } from "./stripe";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "pg",
    schema,
    usePlural: true,
  }),
  appName: process.env.NEXT_PUBLIC_APP_NAME,
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
    requireEmailVerification: true,
    sendResetPassword: async (data) => console.log(data),
  },
  emailVerification: {
    sendOnSignIn: true,
    sendOnSignUp: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async (data) => console.log(data),
  },
  socialProviders: {
    google: {
      enabled: true,
      clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    },
    facebook: {
      enabled: true,
      clientId: process.env.NEXT_PUBLIC_FACEBOOK_APP_ID,
      clientSecret: process.env.FACEBOOK_APP_SECRET,
    },
  },
  account: {
    accountLinking: {
      enabled: true,
      trustedProviders: ["google", "facebook", "email-password"],
    },
  },
  plugins: [
    // Authentication
    twoFactor(),
    username(),
    anonymous(),
    phoneNumber({
      sendOTP: async (data) => console.log(data),
    }),
    magicLink({
      sendMagicLink: async (data) => console.log(data),
    }),
    emailOTP({
      overrideDefaultEmailVerification: true,
      sendVerificationOTP: async (data) => console.log(data),
    }),
    passkey(),
    genericOAuth({
      config: [],
    }),
    oneTap(),
    siwe({
      domain: process.env.NEXT_PUBLIC_APP_DOMAIN,
      emailDomainName: process.env.NEXT_PUBLIC_APP_DOMAIN,
      anonymous: false,
      getNonce: async () => generateRandomString(32),
      verifyMessage: async ({ message, signature, address }) => {
        try {
          const isValid = await verifyMessage({
            address: address as `0x${string}`,
            message,
            signature: signature as `0x${string}`,
          });
          return isValid;
        } catch (error) {
          console.error("SIWE verification failed:", error);
          return false;
        }
      },
      ensLookup: async ({ walletAddress }) => {
        try {
          const client = createPublicClient({
            chain: mainnet,
            transport: http(),
          });
          const ensName = await client.getEnsName({
            address: walletAddress as `0x${string}`,
          });
          const ensAvatar = ensName
            ? await client.getEnsAvatar({ name: ensName })
            : null;
          return {
            name: ensName || walletAddress,
            avatar: ensAvatar || "",
          };
        } catch {
          return { name: walletAddress, avatar: "" };
        }
      },
    }),
    // Authorization
    admin(),
    apiKey(),
    mcp({
      loginPage: "/sign-in",
    }),
    organization(),
    // Enterprise
    oidcProvider({
      loginPage: "/sign-in",
    }),
    sso(),
    scim(),
    // Utility
    bearer(),
    deviceAuthorization({
      verificationUri: "/device",
    }),
    captcha({
      provider: "cloudflare-turnstile",
      secretKey: process.env.TURNSTILE_SECRET_KEY,
    }),
    haveIBeenPwned(),
    lastLoginMethod({
      storeInDatabase: true,
    }),
    multiSession(),
    oAuthProxy(),
    oneTimeToken(),
    openAPI(),
    jwt(),
    // 3rd party
    stripe({
      stripeClient,
      stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
      createCustomerOnSignUp: true,
      subscription: {
        enabled: true,
        plans: [],
      },
    }),
    // Cookies
    nextCookies(),
  ],
  experimental: {
    joins: true,
  },
});

Additional context

No response

Originally created by @bennajah on GitHub (Nov 24, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. install `mcp` and `oidcProvider` plusins 2. run `npx @better-auth/cli generate` 3. see error ### Current vs. Expected behavior ```PS [Better Auth]: Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods: - "/oauth2/consent" [POST] used by plugins: mcp, oidc To resolve this, you can: 1. Use only one of the conflicting plugins 2. Configure the plugins to use different paths (if supported) 3. Ensure plugins use different HTTP methods for the same path ``` ### What version of Better Auth are you using? 1.4.1 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26200", "cpuCount": 8, "cpuModel": "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz", "totalMemory": "11.96 GB", "freeMemory": "3.99 GB" }, "node": { "version": "v24.3.0", "env": "development" }, "packageManager": { "name": "bun", "version": "1.3.3" }, "frameworks": [ { "name": "next", "version": "^16.0.3" }, { "name": "react", "version": "^19.2.0" } ], "databases": [ { "name": "drizzle", "version": "^0.44.7" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.4.1", "config": { "appName": "my-app", "emailAndPassword": { "enabled": true, "autoSignIn": true, "requireEmailVerification": true }, "emailVerification": { "sendOnSignIn": true, "sendOnSignUp": true, "autoSignInAfterVerification": true }, "socialProviders": { "google": { "enabled": true, "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" }, "facebook": { "enabled": true, "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "account": { "accountLinking": { "enabled": true, "trustedProviders": ["google", "facebook", "email-password"] } }, "plugins": [ { "name": "two-factor", "config": { "id": "two-factor", "endpoints": {}, "hooks": { "after": [{}] }, "schema": { "user": { "fields": { "twoFactorEnabled": { "type": "boolean", "required": false, "defaultValue": false, "input": false } } }, "twoFactor": { "fields": { "secret": { "type": "string", "required": true, "returned": false, "index": true }, "backupCodes": { "type": "string", "required": true, "returned": false }, "userId": { "type": "string", "required": true, "returned": false, "references": { "model": "user", "field": "id" }, "index": true } } } }, "rateLimit": [ { "window": 10, "max": 3 } ], "$ERROR_CODES": { "OTP_NOT_ENABLED": "OTP not enabled", "OTP_HAS_EXPIRED": "OTP has expired", "TOTP_NOT_ENABLED": "TOTP not enabled", "TWO_FACTOR_NOT_ENABLED": "Two factor isn't enabled", "BACKUP_CODES_NOT_ENABLED": "Backup codes aren't enabled", "INVALID_BACKUP_CODE": "Invalid backup code", "INVALID_CODE": "Invalid code", "TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE": "Too many attempts. Please request a new code.", "INVALID_TWO_FACTOR_COOKIE": "Invalid two factor cookie" } } }, { "name": "username", "config": { "id": "username", "endpoints": {}, "schema": { "user": { "fields": { "username": { "type": "string", "required": false, "sortable": true, "unique": true, "returned": true, "transform": {} }, "displayUsername": { "type": "string", "required": false, "transform": {} } } } }, "hooks": { "before": [{}, {}] }, "$ERROR_CODES": { "INVALID_USERNAME_OR_PASSWORD": "[REDACTED]", "EMAIL_NOT_VERIFIED": "Email not verified", "UNEXPECTED_ERROR": "Unexpected error", "USERNAME_IS_ALREADY_TAKEN": "Username is already taken. Please try another.", "USERNAME_TOO_SHORT": "Username is too short", "USERNAME_TOO_LONG": "Username is too long", "INVALID_USERNAME": "Username is invalid", "INVALID_DISPLAY_USERNAME": "Display username is invalid" } } }, { "name": "anonymous", "config": { "id": "anonymous", "endpoints": {}, "hooks": { "after": [{}] }, "schema": { "user": { "fields": { "isAnonymous": { "type": "boolean", "required": false, "input": false, "defaultValue": false } } } }, "$ERROR_CODES": { "INVALID_EMAIL_FORMAT": "Email was not generated in a valid format", "FAILED_TO_CREATE_USER": "Failed to create user", "COULD_NOT_CREATE_SESSION": "Could not create session", "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": "Anonymous users cannot sign in again anonymously" } } }, { "name": "phone-number", "config": { "id": "phone-number", "hooks": { "before": [{}] }, "endpoints": {}, "schema": { "user": { "fields": { "phoneNumber": { "type": "string", "required": false, "unique": true, "sortable": true, "returned": true }, "phoneNumberVerified": { "type": "boolean", "required": false, "returned": true, "input": false } } } }, "rateLimit": [ { "window": 60000, "max": 10 } ], "$ERROR_CODES": { "INVALID_PHONE_NUMBER": "Invalid phone number", "PHONE_NUMBER_EXIST": "Phone number already exists", "PHONE_NUMBER_NOT_EXIST": "phone number isn't registered", "INVALID_PHONE_NUMBER_OR_PASSWORD": "[REDACTED]", "UNEXPECTED_ERROR": "Unexpected error", "OTP_NOT_FOUND": "OTP not found", "OTP_EXPIRED": "OTP expired", "INVALID_OTP": "Invalid OTP", "PHONE_NUMBER_NOT_VERIFIED": "Phone number not verified", "PHONE_NUMBER_CANNOT_BE_UPDATED": "Phone number cannot be updated", "SEND_OTP_NOT_IMPLEMENTED": "sendOTP not implemented", "TOO_MANY_ATTEMPTS": "Too many attempts" } } }, { "name": "magic-link", "config": { "id": "magic-link", "endpoints": {}, "rateLimit": [ { "window": 60, "max": 5 } ] } }, { "name": "email-otp", "config": { "id": "email-otp", "endpoints": {}, "hooks": { "after": [{}] }, "$ERROR_CODES": { "OTP_EXPIRED": "OTP expired", "INVALID_OTP": "Invalid OTP", "TOO_MANY_ATTEMPTS": "Too many attempts" }, "rateLimit": [ { "window": 60, "max": 3 }, { "window": 60, "max": 3 }, { "window": 60, "max": 3 }, { "window": 60, "max": 3 } ] } }, { "name": "passkey", "config": { "id": "passkey", "endpoints": {}, "schema": { "passkey": { "fields": { "name": { "type": "string", "required": false }, "publicKey": { "type": "string", "required": true }, "userId": { "type": "string", "references": { "model": "user", "field": "id" }, "required": true, "index": true }, "credentialID": { "type": "string", "required": true, "index": true }, "counter": { "type": "number", "required": true }, "deviceType": { "type": "string", "required": true }, "backedUp": { "type": "boolean", "required": true }, "transports": { "type": "string", "required": false }, "createdAt": { "type": "date", "required": false }, "aaguid": { "type": "string", "required": false } } } }, "$ERROR_CODES": { "CHALLENGE_NOT_FOUND": "Challenge not found", "YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY": "You are not allowed to register this passkey", "FAILED_TO_VERIFY_REGISTRATION": "Failed to verify registration", "PASSKEY_NOT_FOUND": "Passkey not found", "AUTHENTICATION_FAILED": "Authentication failed", "UNABLE_TO_CREATE_SESSION": "Unable to create session", "FAILED_TO_UPDATE_PASSKEY": "Failed to update passkey" } } }, { "name": "generic-oauth", "config": { "id": "generic-oauth", "endpoints": {}, "$ERROR_CODES": { "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration", "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.", "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider", "PROVIDER_ID_REQUIRED": "Provider ID is required", "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.", "SESSION_REQUIRED": "Session is required" } } }, { "name": "one-tap", "config": { "id": "one-tap", "endpoints": {} } }, { "name": "siwe", "config": { "id": "siwe", "schema": { "walletAddress": { "fields": { "userId": { "type": "string", "references": { "model": "user", "field": "id" }, "required": true, "index": true }, "address": { "type": "string", "required": true }, "chainId": { "type": "number", "required": true }, "isPrimary": { "type": "boolean", "defaultValue": false }, "createdAt": { "type": "date", "required": true } } } }, "endpoints": {} } }, { "name": "admin", "config": { "id": "admin", "hooks": { "after": [{}] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists.", "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.", "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself", "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions", "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users", "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users", "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions", "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users", "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]", "BANNED_USER": "You have been banned from this application", "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users", "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself", "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value" }, "schema": { "user": { "fields": { "role": { "type": "string", "required": false, "input": false }, "banned": { "type": "boolean", "defaultValue": false, "required": false, "input": false }, "banReason": { "type": "string", "required": false, "input": false }, "banExpires": { "type": "date", "required": false, "input": false } } }, "session": { "fields": { "impersonatedBy": { "type": "string", "required": false } } } } } }, { "name": "api-key", "config": { "id": "api-key", "$ERROR_CODES": { "INVALID_METADATA_TYPE": "metadata must be an object or undefined", "REFILL_AMOUNT_AND_INTERVAL_REQUIRED": "refillAmount is required when refillInterval is provided", "REFILL_INTERVAL_AND_AMOUNT_REQUIRED": "refillInterval is required when refillAmount is provided", "USER_BANNED": "User is banned", "UNAUTHORIZED_SESSION": "Unauthorized or invalid session", "KEY_NOT_FOUND": "API Key not found", "KEY_DISABLED": "API Key is disabled", "KEY_EXPIRED": "API Key has expired", "USAGE_EXCEEDED": "API Key has reached its usage limit", "KEY_NOT_RECOVERABLE": "API Key is not recoverable", "EXPIRES_IN_IS_TOO_SMALL": "The expiresIn is smaller than the predefined minimum value.", "EXPIRES_IN_IS_TOO_LARGE": "The expiresIn is larger than the predefined maximum value.", "INVALID_REMAINING": "The remaining count is either too large or too small.", "INVALID_PREFIX_LENGTH": "The prefix length is either too large or too small.", "INVALID_NAME_LENGTH": "The name length is either too large or too small.", "METADATA_DISABLED": "Metadata is disabled.", "RATE_LIMIT_EXCEEDED": "Rate limit exceeded.", "NO_VALUES_TO_UPDATE": "No values to update.", "KEY_DISABLED_EXPIRATION": "Custom key expiration values are disabled.", "INVALID_API_KEY": "Invalid API key.", "INVALID_USER_ID_FROM_API_KEY": "The user id from the API key is invalid.", "INVALID_API_KEY_GETTER_RETURN_TYPE": "API Key getter returned an invalid key type. Expected string.", "SERVER_ONLY_PROPERTY": "The property you're trying to set can only be set from the server auth instance only.", "FAILED_TO_UPDATE_API_KEY": "Failed to update API key", "NAME_REQUIRED": "API Key name is required." }, "hooks": { "before": [{}] }, "endpoints": {}, "schema": { "apikey": { "fields": { "name": { "type": "string", "required": false, "input": false }, "start": { "type": "string", "required": false, "input": false }, "prefix": { "type": "string", "required": false, "input": false }, "key": { "type": "string", "required": true, "input": false, "index": true }, "userId": { "type": "string", "references": { "model": "user", "field": "id", "onDelete": "cascade" }, "required": true, "input": false, "index": true }, "refillInterval": { "type": "number", "required": false, "input": false }, "refillAmount": { "type": "number", "required": false, "input": false }, "lastRefillAt": { "type": "date", "required": false, "input": false }, "enabled": { "type": "boolean", "required": false, "input": false, "defaultValue": true }, "rateLimitEnabled": { "type": "boolean", "required": false, "input": false, "defaultValue": true }, "rateLimitTimeWindow": { "type": "number", "required": false, "input": false, "defaultValue": 86400000 }, "rateLimitMax": { "type": "number", "required": false, "input": false, "defaultValue": 10 }, "requestCount": { "type": "number", "required": false, "input": false, "defaultValue": 0 }, "remaining": { "type": "number", "required": false, "input": false }, "lastRequest": { "type": "date", "required": false, "input": false }, "expiresAt": { "type": "date", "required": false, "input": false }, "createdAt": { "type": "date", "required": true, "input": false }, "updatedAt": { "type": "date", "required": true, "input": false }, "permissions": { "type": "string", "required": false, "input": false }, "metadata": { "type": "string", "required": false, "input": true, "transform": {} } } } } } }, { "name": "mcp", "config": { "id": "mcp", "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" }, "index": true }, "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" }, "index": true }, "userId": { "type": "string", "required": false, "references": { "model": "user", "field": "id", "onDelete": "cascade" }, "index": true }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" } } }, "oauthConsent": { "modelName": "oauthConsent", "fields": { "clientId": { "type": "string", "references": { "model": "oauthApplication", "field": "clientId", "onDelete": "cascade" }, "index": true }, "userId": { "type": "string", "references": { "model": "user", "field": "id", "onDelete": "cascade" }, "index": true }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" }, "consentGiven": { "type": "boolean" } } } } } }, { "name": "organization", "config": { "id": "organization", "endpoints": {}, "schema": { "organization": { "fields": { "name": { "type": "string", "required": true, "sortable": true }, "slug": { "type": "string", "required": true, "unique": true, "sortable": true }, "logo": { "type": "string", "required": false }, "createdAt": { "type": "date", "required": true }, "metadata": { "type": "string", "required": false } } }, "member": { "fields": { "organizationId": { "type": "string", "required": true, "references": { "model": "organization", "field": "id" }, "index": true }, "userId": { "type": "string", "required": true, "references": { "model": "user", "field": "id" }, "index": true }, "role": { "type": "string", "required": true, "sortable": true, "defaultValue": "member" }, "createdAt": { "type": "date", "required": true } } }, "invitation": { "fields": { "organizationId": { "type": "string", "required": true, "references": { "model": "organization", "field": "id" }, "index": true }, "email": { "type": "string", "required": true, "sortable": true, "index": true }, "role": { "type": "string", "required": false, "sortable": true }, "status": { "type": "string", "required": true, "sortable": true, "defaultValue": "pending" }, "expiresAt": { "type": "date", "required": true }, "createdAt": { "type": "date", "required": true }, "inviterId": { "type": "string", "references": { "model": "user", "field": "id" }, "required": true } } }, "session": { "fields": { "activeOrganizationId": { "type": "string", "required": false } } } }, "$Infer": { "Organization": {}, "Invitation": {}, "Member": {}, "Team": {}, "TeamMember": {}, "ActiveOrganization": {} }, "$ERROR_CODES": { "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION": "You are not allowed to create a new organization", "YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS": "You have reached the maximum number of organizations", "ORGANIZATION_ALREADY_EXISTS": "Organization already exists", "ORGANIZATION_SLUG_ALREADY_TAKEN": "Organization slug already taken", "ORGANIZATION_NOT_FOUND": "Organization not found", "USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION": "User is not a member of the organization", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION": "You are not allowed to update this organization", "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION": "You are not allowed to delete this organization", "NO_ACTIVE_ORGANIZATION": "No active organization", "USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION": "User is already a member of this organization", "MEMBER_NOT_FOUND": "Member not found", "ROLE_NOT_FOUND": "Role not found", "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM": "You are not allowed to create a new team", "TEAM_ALREADY_EXISTS": "Team already exists", "TEAM_NOT_FOUND": "Team not found", "YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER": "You cannot leave the organization as the only owner", "YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER": "You cannot leave the organization without an owner", "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER": "You are not allowed to delete this member", "YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION": "You are not allowed to invite users to this organization", "USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION": "User is already invited to this organization", "INVITATION_NOT_FOUND": "Invitation not found", "YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION": "You are not the recipient of the invitation", "EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION": "Email verification required before accepting or rejecting invitation", "YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION": "You are not allowed to cancel this invitation", "INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION": "Inviter is no longer a member of the organization", "YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE": "You are not allowed to invite a user with this role", "FAILED_TO_RETRIEVE_INVITATION": "Failed to retrieve invitation", "YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS": "You have reached the maximum number of teams", "UNABLE_TO_REMOVE_LAST_TEAM": "Unable to remove last team", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER": "You are not allowed to update this member", "ORGANIZATION_MEMBERSHIP_LIMIT_REACHED": "Organization membership limit reached", "YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION": "You are not allowed to create teams in this organization", "YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION": "You are not allowed to delete teams in this organization", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM": "You are not allowed to update this team", "YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM": "You are not allowed to delete this team", "INVITATION_LIMIT_REACHED": "Invitation limit reached", "TEAM_MEMBER_LIMIT_REACHED": "Team member limit reached", "USER_IS_NOT_A_MEMBER_OF_THE_TEAM": "User is not a member of the team", "YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM": "You are not allowed to list the members of this team", "YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM": "You do not have an active team", "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER": "You are not allowed to create a new member", "YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER": "You are not allowed to remove a team member", "YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION": "You are not allowed to access this organization as an owner", "YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION": "You are not a member of this organization", "MISSING_AC_INSTANCE": "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information", "YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE": "You must be in an organization to create a role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE": "You are not allowed to create a role", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE": "You are not allowed to update a role", "YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE": "You are not allowed to delete a role", "YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE": "You are not allowed to read a role", "YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE": "You are not allowed to list a role", "YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE": "You are not allowed to get a role", "TOO_MANY_ROLES": "This organization has too many roles", "INVALID_RESOURCE": "The provided permission includes an invalid resource", "ROLE_NAME_IS_ALREADY_TAKEN": "That role name is already taken", "CANNOT_DELETE_A_PRE_DEFINED_ROLE": "Cannot delete a pre-defined role" } } }, { "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" }, "index": true }, "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" }, "index": true }, "userId": { "type": "string", "required": false, "references": { "model": "user", "field": "id", "onDelete": "cascade" }, "index": true }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" } } }, "oauthConsent": { "modelName": "oauthConsent", "fields": { "clientId": { "type": "string", "references": { "model": "oauthApplication", "field": "clientId", "onDelete": "cascade" }, "index": true }, "userId": { "type": "string", "references": { "model": "user", "field": "id", "onDelete": "cascade" }, "index": true }, "scopes": { "type": "string" }, "createdAt": { "type": "date" }, "updatedAt": { "type": "date" }, "consentGiven": { "type": "boolean" } } } }, "options": { "codeExpiresIn": 600, "defaultScope": "openid", "accessTokenExpiresIn": 3600, "refreshTokenExpiresIn": 604800, "allowPlainCodeChallengeMethod": true, "storeClientSecret": "[REDACTED]", "loginPage": "/sign-in", "scopes": ["openid", "profile", "email", "offline_access"] } } }, { "name": "sso", "config": { "id": "sso", "endpoints": {}, "schema": { "ssoProvider": { "modelName": "ssoProvider", "fields": { "issuer": { "type": "string", "required": true, "fieldName": "issuer" }, "oidcConfig": { "type": "string", "required": false, "fieldName": "oidcConfig" }, "samlConfig": { "type": "string", "required": false, "fieldName": "samlConfig" }, "userId": { "type": "string", "references": { "model": "user", "field": "id" }, "fieldName": "userId" }, "providerId": { "type": "string", "required": true, "unique": true, "fieldName": "providerId" }, "organizationId": { "type": "string", "required": false, "fieldName": "organizationId" }, "domain": { "type": "string", "required": true, "fieldName": "domain" } } } } } }, { "name": "scim", "config": { "id": "scim", "endpoints": {}, "schema": { "scimProvider": { "fields": { "providerId": { "type": "string", "required": true, "unique": true }, "scimToken": { "type": "string", "required": true, "unique": true }, "organizationId": { "type": "string", "required": false } } } } } }, { "name": "bearer", "config": { "id": "bearer", "hooks": { "before": [{}], "after": [{}] } } }, { "name": "device-authorization", "config": { "id": "device-authorization", "schema": { "deviceCode": { "fields": { "deviceCode": { "type": "string", "required": true }, "userCode": { "type": "string", "required": true }, "userId": { "type": "string", "required": false }, "expiresAt": { "type": "date", "required": true }, "status": { "type": "string", "required": true }, "lastPolledAt": { "type": "date", "required": false }, "pollingInterval": { "type": "number", "required": false }, "clientId": { "type": "string", "required": false }, "scope": { "type": "string", "required": false } } } }, "endpoints": {}, "$ERROR_CODES": { "INVALID_DEVICE_CODE": "Invalid device code", "EXPIRED_DEVICE_CODE": "Device code has expired", "EXPIRED_USER_CODE": "User code has expired", "AUTHORIZATION_PENDING": "Authorization pending", "ACCESS_DENIED": "Access denied", "INVALID_USER_CODE": "Invalid user code", "DEVICE_CODE_ALREADY_PROCESSED": "Device code already processed", "POLLING_TOO_FREQUENTLY": "Polling too frequently", "USER_NOT_FOUND": "User not found", "FAILED_TO_CREATE_SESSION": "Failed to create session", "INVALID_DEVICE_CODE_STATUS": "Invalid device code status", "AUTHENTICATION_REQUIRED": "Authentication required" } } }, { "name": "captcha", "config": { "id": "captcha" } }, { "name": "haveIBeenPwned", "config": { "id": "haveIBeenPwned", "$ERROR_CODES": { "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password." } } }, { "name": "last-login-method", "config": { "id": "last-login-method", "hooks": { "after": [{}] }, "schema": { "user": { "fields": { "lastLoginMethod": { "type": "string", "input": false, "required": false, "fieldName": "lastLoginMethod" } } } } } }, { "name": "multi-session", "config": { "id": "multi-session", "endpoints": {}, "hooks": { "after": [{}, {}] }, "$ERROR_CODES": { "INVALID_SESSION_TOKEN": "[REDACTED]" } } }, { "name": "oauth-proxy", "config": { "id": "oauth-proxy", "endpoints": {}, "hooks": { "before": [{}, {}, {}], "after": [{}, {}, {}] } } }, { "name": "one-time-token", "config": { "id": "one-time-token", "endpoints": {} } }, { "name": "open-api", "config": { "id": "open-api", "endpoints": {} } }, { "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 }, "expiresAt": { "type": "date", "required": false } } } } } }, { "name": "stripe", "config": { "id": "stripe", "endpoints": {}, "schema": { "subscription": { "fields": { "plan": { "type": "string", "required": true }, "referenceId": { "type": "string", "required": true }, "stripeCustomerId": { "type": "string", "required": false }, "stripeSubscriptionId": { "type": "string", "required": false }, "status": { "type": "string", "defaultValue": "incomplete" }, "periodStart": { "type": "date", "required": false }, "periodEnd": { "type": "date", "required": false }, "trialStart": { "type": "date", "required": false }, "trialEnd": { "type": "date", "required": false }, "cancelAtPeriodEnd": { "type": "boolean", "required": false, "defaultValue": false }, "seats": { "type": "number", "required": false } } }, "user": { "fields": { "stripeCustomerId": { "type": "string", "required": false } } } }, "$ERROR_CODES": { "SUBSCRIPTION_NOT_FOUND": "Subscription not found", "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found", "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan", "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer", "FAILED_TO_FETCH_PLANS": "Failed to fetch plans", "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan", "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active", "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation" } } }, { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [{}] } } } ], "experimental": { "joins": true } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend, Client ### Auth config (if applicable) ```typescript import { passkey } from "@better-auth/passkey"; import { scim } from "@better-auth/scim"; import { sso } from "@better-auth/sso"; import { stripe } from "@better-auth/stripe"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { generateRandomString } from "better-auth/crypto"; import { nextCookies } from "better-auth/next-js"; import { admin, anonymous, apiKey, bearer, captcha, deviceAuthorization, emailOTP, genericOAuth, haveIBeenPwned, jwt, lastLoginMethod, magicLink, mcp, multiSession, oAuthProxy, oidcProvider, oneTap, oneTimeToken, openAPI, organization, phoneNumber, siwe, twoFactor, username, } from "better-auth/plugins"; import { createPublicClient, http, verifyMessage } from "viem"; import { mainnet } from "viem/chains"; import { db } from "@/db"; // biome-ignore lint/performance/noNamespaceImport: "" import * as schema from "@/db/schema"; import { stripe as stripeClient } from "./stripe"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema, usePlural: true, }), appName: process.env.NEXT_PUBLIC_APP_NAME, emailAndPassword: { enabled: true, autoSignIn: true, requireEmailVerification: true, sendResetPassword: async (data) => console.log(data), }, emailVerification: { sendOnSignIn: true, sendOnSignUp: true, autoSignInAfterVerification: true, sendVerificationEmail: async (data) => console.log(data), }, socialProviders: { google: { enabled: true, clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }, facebook: { enabled: true, clientId: process.env.NEXT_PUBLIC_FACEBOOK_APP_ID, clientSecret: process.env.FACEBOOK_APP_SECRET, }, }, account: { accountLinking: { enabled: true, trustedProviders: ["google", "facebook", "email-password"], }, }, plugins: [ // Authentication twoFactor(), username(), anonymous(), phoneNumber({ sendOTP: async (data) => console.log(data), }), magicLink({ sendMagicLink: async (data) => console.log(data), }), emailOTP({ overrideDefaultEmailVerification: true, sendVerificationOTP: async (data) => console.log(data), }), passkey(), genericOAuth({ config: [], }), oneTap(), siwe({ domain: process.env.NEXT_PUBLIC_APP_DOMAIN, emailDomainName: process.env.NEXT_PUBLIC_APP_DOMAIN, anonymous: false, getNonce: async () => generateRandomString(32), verifyMessage: async ({ message, signature, address }) => { try { const isValid = await verifyMessage({ address: address as `0x${string}`, message, signature: signature as `0x${string}`, }); return isValid; } catch (error) { console.error("SIWE verification failed:", error); return false; } }, ensLookup: async ({ walletAddress }) => { try { const client = createPublicClient({ chain: mainnet, transport: http(), }); const ensName = await client.getEnsName({ address: walletAddress as `0x${string}`, }); const ensAvatar = ensName ? await client.getEnsAvatar({ name: ensName }) : null; return { name: ensName || walletAddress, avatar: ensAvatar || "", }; } catch { return { name: walletAddress, avatar: "" }; } }, }), // Authorization admin(), apiKey(), mcp({ loginPage: "/sign-in", }), organization(), // Enterprise oidcProvider({ loginPage: "/sign-in", }), sso(), scim(), // Utility bearer(), deviceAuthorization({ verificationUri: "/device", }), captcha({ provider: "cloudflare-turnstile", secretKey: process.env.TURNSTILE_SECRET_KEY, }), haveIBeenPwned(), lastLoginMethod({ storeInDatabase: true, }), multiSession(), oAuthProxy(), oneTimeToken(), openAPI(), jwt(), // 3rd party stripe({ stripeClient, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET, createCustomerOnSignUp: true, subscription: { enabled: true, plans: [], }, }), // Cookies nextCookies(), ], experimental: { joins: true, }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 09:48:34 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Nov 24, 2025):

This conflict happens because both the mcp and oidcProvider plugins register a POST endpoint at /oauth2/consent. The mcp plugin actually wraps and re-exports the endpoints from oidcProvider, so when you include both, Better Auth detects that they both try to handle the same path and method, which isn't allowed [source].

There are currently no config options in either plugin to change this endpoint path or avoid the conflict. The only supported workaround is to use just one of these plugins at a time, or to patch the code to change the endpoint path if you really need both (which is not recommended) [source].

This is a known limitation, not a bug, and is enforced by Better Auth's endpoint conflict detection logic as of v1.4.1 [source]. There is an open pull request to unify or refactor these plugins, which should eventually resolve this kind of conflict [source]. For now, you’ll need to pick one plugin for your OAuth/OIDC flows.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 24, 2025): <!-- Answer --> This conflict happens because both the `mcp` and `oidcProvider` plugins register a POST endpoint at `/oauth2/consent`. The `mcp` plugin actually wraps and re-exports the endpoints from `oidcProvider`, so when you include both, Better Auth detects that they both try to handle the same path and method, which isn't allowed [[source]](https://github.com/better-auth/better-auth/blob/fc662c52dcadc9874d36bd354d53d23f8a24e098/packages/better-auth/src/plugins/mcp/index.ts#L32-L941). There are currently no config options in either plugin to change this endpoint path or avoid the conflict. The only supported workaround is to use just one of these plugins at a time, or to patch the code to change the endpoint path if you really need both (which is not recommended) [[source]](https://github.com/better-auth/better-auth/issues/3595). This is a known limitation, not a bug, and is enforced by Better Auth's endpoint conflict detection logic as of v1.4.1 [[source]](https://github.com/better-auth/better-auth/pull/4288). There is an open pull request to unify or refactor these plugins, which should eventually resolve this kind of conflict [[source]](https://github.com/better-auth/better-auth/pull/4057). For now, you’ll need to pick one plugin for your OAuth/OIDC flows. <!-- 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/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/82352554-1e8a-4afc-b911-76ed2a20d4db?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20conflict%20happens%20because%20both%20the%20%60mcp%60%20and%20%60oidcProvider%60%20plugins%20register%20a%20POST%20endpoint%20at%20%60/oauth2/consent%60.%20The%20%60mcp%60%20plugin%20actually%20wraps%20and%20re-exports%20the%20endpoints%20from%20%60oidcProvider%60%2C%20so%20when%20you%20include%20both%2C%20Better%20Auth%20detects%20that%20they%20both%20try%20to%20handle%20the%20same%20path%20and%20method%2C%20which%20isn%27t%20allowed%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/blob/fc662c52dcadc9874d36bd354d53d23f8a24e098/packages/better-auth/src/plugins/mcp/index.ts%23L32-L941%29.%0A%0AThere%20are%20currently%20no%20config%20options%20in%20either%20plugin%20to%20change%20this%20endpoint%20path%20or%20avoid%20the%20conflict.%20The%20only%20supported%20workaround%20is%20to%20use%20just%20one%20of%20these%20plugins%20at%20a%20time%2C%20or%20to%20patch%20the%20code%20to%20change%20the%20endpoint%20path%20if%20you%20really%20need%20both%20%28which%20is%20not%20recommended%29%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/3595%29.%0A%0AThis%20is%20a%20known%20limitation%2C%20not%20a%20bug%2C%20and%20is%20enforced%20by%20Better%20Auth%27s%20endpoint%20conflict%20detection%20logic%20as%20of%20v1.4.1%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/pull/4288%29.%20There%20is%20an%20open%20pull%20request%20to%20unify%20or%20refactor%20these%20plugins%2C%20which%20should%20eventually%20resolve%20this%20kind%20of%20conflict%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/pull/4057%29.%20For%20now%2C%20you%E2%80%99ll%20need%20to%20pick%20one%20plugin%20for%20your%20OAuth/OIDC%20flows.)&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/6270)
Author
Owner

@bennajah commented on GitHub (Nov 24, 2025):

also in src\app\.well-known\oauth-authorization-server\route.ts

import { oAuthDiscoveryMetadata } from "better-auth/plugins";
import { auth } from "../../../lib/auth";

export const GET = oAuthDiscoveryMetadata(auth);

and in src\app\.well-known\oauth-protected-resource\route.ts

import { oAuthProtectedResourceMetadata } from "better-auth/plugins";
import { auth } from "../../../lib/auth";

export const GET = oAuthProtectedResourceMetadata(auth);

getting typescript error

Argument of type 'Auth<BetterAuthOptions>' is not assignable to parameter of type '{ api: { getMCPProtectedResource: (...args: any) => any; }; }'.
  Types of property 'api' are incompatible.
    Property 'getMCPProtectedResource' is missing in type 'InferAPI<{ readonly ok: StrictEndpoint<"/ok", { method: "GET"; metadata: { openapi: { description: string; responses: { "200": { description: string; content: { "application/json": { schema: { type: "object"; properties: { ok: { type: string; description: string; }; }; required: string[]; }; }; }; }; }; }; isAction:...' but required in type '{ getMCPProtectedResource: (...args: any) => any; }'.ts(2345)
index-BLP8lbCx.d.mts(4757, 5): 'getMCPProtectedResource' is declared here.
@bennajah commented on GitHub (Nov 24, 2025): also in `src\app\.well-known\oauth-authorization-server\route.ts` ```ts import { oAuthDiscoveryMetadata } from "better-auth/plugins"; import { auth } from "../../../lib/auth"; export const GET = oAuthDiscoveryMetadata(auth); ``` and in `src\app\.well-known\oauth-protected-resource\route.ts` ```ts import { oAuthProtectedResourceMetadata } from "better-auth/plugins"; import { auth } from "../../../lib/auth"; export const GET = oAuthProtectedResourceMetadata(auth); ``` getting typescript error ```ts Argument of type 'Auth<BetterAuthOptions>' is not assignable to parameter of type '{ api: { getMCPProtectedResource: (...args: any) => any; }; }'. Types of property 'api' are incompatible. Property 'getMCPProtectedResource' is missing in type 'InferAPI<{ readonly ok: StrictEndpoint<"/ok", { method: "GET"; metadata: { openapi: { description: string; responses: { "200": { description: string; content: { "application/json": { schema: { type: "object"; properties: { ok: { type: string; description: string; }; }; required: string[]; }; }; }; }; }; }; isAction:...' but required in type '{ getMCPProtectedResource: (...args: any) => any; }'.ts(2345) index-BLP8lbCx.d.mts(4757, 5): 'getMCPProtectedResource' is declared here. ```
Author
Owner

@dosubot[bot] commented on GitHub (Nov 24, 2025):

The TypeScript error happens because oAuthDiscoveryMetadata and oAuthProtectedResourceMetadata expect your auth instance to have specific API methods—getMcpOAuthConfig and getMCPProtectedResource—which are only provided by the MCP plugin. If your auth instance doesn't include MCP (or if there's a type inference issue and TypeScript can't see those methods), you'll get this error.

To fix it, make sure the MCP plugin is included in your Better Auth config and that it's not shadowed by type conflicts with other plugins. If you need both MCP and OIDC, be aware that they can conflict and Better Auth doesn't currently support namespacing or aliasing for overlapping endpoints [source].

If you still get type errors, you can work around them by explicitly typing your auth instance to include the MCP plugin's API methods, or by serving static metadata for these endpoints if you don't need dynamic JWKS or other runtime data [source].

Known TypeScript limitations with plugin APIs mean you may need to use explicit type annotations or tweak your tsconfig to get proper inference [source].

Let me know if you need a concrete example of how to type your auth instance or route handler!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 24, 2025): <!-- Answer --> The TypeScript error happens because `oAuthDiscoveryMetadata` and `oAuthProtectedResourceMetadata` expect your `auth` instance to have specific API methods—`getMcpOAuthConfig` and `getMCPProtectedResource`—which are only provided by the MCP plugin. If your `auth` instance doesn't include MCP (or if there's a type inference issue and TypeScript can't see those methods), you'll get this error. To fix it, make sure the MCP plugin is included in your Better Auth config and that it's not shadowed by type conflicts with other plugins. If you need both MCP and OIDC, be aware that they can conflict and Better Auth doesn't currently support namespacing or aliasing for overlapping endpoints [[source]](https://github.com/better-auth/better-auth/blob/fc662c52dcadc9874d36bd354d53d23f8a24e098/packages/better-auth/src/plugins/mcp/index.ts#L187-L1041). If you still get type errors, you can work around them by explicitly typing your auth instance to include the MCP plugin's API methods, or by serving static metadata for these endpoints if you don't need dynamic JWKS or other runtime data [[source]](https://github.com/better-auth/better-auth/issues/3725). Known TypeScript limitations with plugin APIs mean you may need to use explicit type annotations or tweak your tsconfig to get proper inference [[source]](https://github.com/better-auth/better-auth/issues/1391). Let me know if you need a concrete example of how to type your auth instance or route handler! <!-- 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/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/05c378dc-8a29-4d58-918d-afb47e378600?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20TypeScript%20error%20happens%20because%20%60oAuthDiscoveryMetadata%60%20and%20%60oAuthProtectedResourceMetadata%60%20expect%20your%20%60auth%60%20instance%20to%20have%20specific%20API%20methods%E2%80%94%60getMcpOAuthConfig%60%20and%20%60getMCPProtectedResource%60%E2%80%94which%20are%20only%20provided%20by%20the%20MCP%20plugin.%20If%20your%20%60auth%60%20instance%20doesn%27t%20include%20MCP%20%28or%20if%20there%27s%20a%20type%20inference%20issue%20and%20TypeScript%20can%27t%20see%20those%20methods%29%2C%20you%27ll%20get%20this%20error.%20%0A%0ATo%20fix%20it%2C%20make%20sure%20the%20MCP%20plugin%20is%20included%20in%20your%20Better%20Auth%20config%20and%20that%20it%27s%20not%20shadowed%20by%20type%20conflicts%20with%20other%20plugins.%20If%20you%20need%20both%20MCP%20and%20OIDC%2C%20be%20aware%20that%20they%20can%20conflict%20and%20Better%20Auth%20doesn%27t%20currently%20support%20namespacing%20or%20aliasing%20for%20overlapping%20endpoints%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/blob/fc662c52dcadc9874d36bd354d53d23f8a24e098/packages/better-auth/src/plugins/mcp/index.ts%23L187-L1041%29.%0A%0AIf%20you%20still%20get%20type%20errors%2C%20you%20can%20work%20around%20them%20by%20explicitly%20typing%20your%20auth%20instance%20to%20include%20the%20MCP%20plugin%27s%20API%20methods%2C%20or%20by%20serving%20static%20metadata%20for%20these%20endpoints%20if%20you%20don%27t%20need%20dynamic%20JWKS%20or%20other%20runtime%20data%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/3725%29.%0A%0AKnown%20TypeScript%20limitations%20with%20plugin%20APIs%20mean%20you%20may%20need%20to%20use%20explicit%20type%20annotations%20or%20tweak%20your%20tsconfig%20to%20get%20proper%20inference%20%5B%5Bsource%5D%5D%28https%3A//github.com/better-auth/better-auth/issues/1391%29.%0A%0ALet%20me%20know%20if%20you%20need%20a%20concrete%20example%20of%20how%20to%20type%20your%20auth%20instance%20or%20route%20handler%21)&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/6270)
Author
Owner

@himself65 commented on GitHub (Nov 24, 2025):

/cc @Bekacru

@himself65 commented on GitHub (Nov 24, 2025): /cc @Bekacru
Author
Owner

@dvanmali commented on GitHub (Dec 24, 2025):

Hi all, we released the new OAuth Provider Plugin which fixes the collision of endpoints. Removing both the mcp and oidc plugins and using only oauthProvider plugin will fix this. Feel free to let us know how it works :)

@dvanmali commented on GitHub (Dec 24, 2025): Hi all, we released the new [OAuth Provider Plugin](https://www.better-auth.com/docs/plugins/oauth-provider) which fixes the collision of endpoints. Removing both the `mcp` and `oidc` plugins and using only `oauthProvider` plugin will fix this. Feel free to let us know how it works :)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2382