Invalid OpenAPI 200 response generated for /email-otp/verify-email #2212

Closed
opened 2026-03-13 09:35:00 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @JohnCido on GitHub (Oct 27, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Add Email OTP and OpenAPI plugin to Better Auth
  2. Download OpenAPI spec as JSON

Current vs. Expected behavior

Current:

...
      "/email-otp/verify-email": {
      ...
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "description": "Indicates if the verification was successful",
                      "enum": [
                        true
                      ]
                    },
                    "token": {
                      "type": "string",
                      "nullable": true,
                      "description": "Session token if autoSignInAfterVerification is enabled, otherwise null"
                    },
                    "user": {
                      "$ref": "#/components/schemas/User"
                    },
                    "required": [
                      "status",
                      "token",
                      "user"
                    ]
                  }
                }
              }
            }
          },
...

Expected:

...
      "/email-otp/verify-email": {
      ...
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "description": "Indicates if the verification was successful",
                      "enum": [
                        true
                      ]
                    },
                    "token": {
                      "type": "string",
                      "nullable": true,
                      "description": "Session token if autoSignInAfterVerification is enabled, otherwise null"
                    },
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  },
                  "required": [
                    "status",
                    "token",
                    "user"
                  ]
                }
              }
            }
          },
...

Please note the required was misplaced under properties.

What version of Better Auth are you using?

1.3.32

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.0.0: Wed Sep 17 21:41:45 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T6000",
    "release": "25.0.0",
    "cpuCount": 8,
    "cpuModel": "Apple M1 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.75 GB"
  },
  "node": {
    "version": "v23.9.0",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.2.23"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "Unknown",
    "config": null
  }
}

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

Other

Auth config (if applicable)

import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { bearer, emailOTP, openAPI } from 'better-auth/plugins'

export const auth = betterAuth({
  appName: 'Poker',
  baseURL: process.env.BASE_URL,
  basePath: '/auth',
  database: ...,
  secret: process.env.BETTER_AUTH_SECRET,
  socialProviders: {
    ...
  },
  trustedOrigins: [...],
  advanced: {
    database: {
      generateId: () => uuidv7(),
    },
    cookiePrefix: '...',
  },
  plugins: [
    bearer(),
    ...(showOpenAPI ? [openAPI()] : []),
    emailOTP({
      sendVerificationOTP: async ({ email, otp, type }) => {
        switch (type) {
          case 'sign-in': {
            ...
            break
          }
          default:
            break
        }
      },
      otpLength: 6,
      storeOTP: 'hashed',
    }),
  ],
  telemetry: {
    enabled: false,
  },
})

Additional context

No response

Originally created by @JohnCido on GitHub (Oct 27, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Add `Email OTP` and `OpenAPI` plugin to Better Auth 2. Download OpenAPI spec as JSON ### Current vs. Expected behavior Current: ```json ... "/email-otp/verify-email": { ... "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "boolean", "description": "Indicates if the verification was successful", "enum": [ true ] }, "token": { "type": "string", "nullable": true, "description": "Session token if autoSignInAfterVerification is enabled, otherwise null" }, "user": { "$ref": "#/components/schemas/User" }, "required": [ "status", "token", "user" ] } } } } }, ... ``` Expected: ```json ... "/email-otp/verify-email": { ... "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "boolean", "description": "Indicates if the verification was successful", "enum": [ true ] }, "token": { "type": "string", "nullable": true, "description": "Session token if autoSignInAfterVerification is enabled, otherwise null" }, "user": { "$ref": "#/components/schemas/User" } }, "required": [ "status", "token", "user" ] } } } }, ... ``` Please note the `required` was misplaced under `properties`. ### What version of Better Auth are you using? 1.3.32 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.0.0: Wed Sep 17 21:41:45 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T6000", "release": "25.0.0", "cpuCount": 8, "cpuModel": "Apple M1 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.75 GB" }, "node": { "version": "v23.9.0", "env": "development" }, "packageManager": { "name": "bun", "version": "1.2.23" }, "frameworks": null, "databases": null, "betterAuth": { "version": "Unknown", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Other ### Auth config (if applicable) ```typescript import { betterAuth } from 'better-auth' import { drizzleAdapter } from 'better-auth/adapters/drizzle' import { bearer, emailOTP, openAPI } from 'better-auth/plugins' export const auth = betterAuth({ appName: 'Poker', baseURL: process.env.BASE_URL, basePath: '/auth', database: ..., secret: process.env.BETTER_AUTH_SECRET, socialProviders: { ... }, trustedOrigins: [...], advanced: { database: { generateId: () => uuidv7(), }, cookiePrefix: '...', }, plugins: [ bearer(), ...(showOpenAPI ? [openAPI()] : []), emailOTP({ sendVerificationOTP: async ({ email, otp, type }) => { switch (type) { case 'sign-in': { ... break } default: break } }, otpLength: 6, storeOTP: 'hashed', }), ], telemetry: { enabled: false, }, }) ``` ### Additional context _No response_
GiteaMirror added the plugin label 2026-03-13 09:35:00 -05:00
Author
Owner

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

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

This is a confirmed bug in Better Auth v1.3.32: the OpenAPI schema for /email-otp/verify-email incorrectly places the required array inside properties instead of at the object schema level. This structure is invalid per the OpenAPI spec and will cause issues with tooling and validation. The root cause is in the Email OTP plugin, where the schema is defined with required nested under properties rather than as a sibling to it in the response metadata (source).

There is currently no released fix, but a related open PR aims to address OpenAPI schema generation issues, including problems with the required property placement (source). Until a fix is released, you can manually patch the generated OpenAPI schema in your app after generation to move the required array to the correct location. This manual patch approach is recommended in similar cases for other endpoints as well.

If you need an example of how to patch the schema programmatically, let me know!

To reply, just mention @dosu.


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

@dosubot[bot] commented on GitHub (Oct 27, 2025): <!-- Greeting --> Hi @JohnCido! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a confirmed bug in Better Auth v1.3.32: the OpenAPI schema for `/email-otp/verify-email` incorrectly places the `required` array inside `properties` instead of at the object schema level. This structure is invalid per the OpenAPI spec and will cause issues with tooling and validation. The root cause is in the Email OTP plugin, where the schema is defined with `required` nested under `properties` rather than as a sibling to it in the response metadata ([source](https://github.com/better-auth/better-auth/blob/97cd4a205957002568915b2f8b85c2b9c8de76d9/packages/better-auth/src/plugins/email-otp/index.ts)). There is currently no released fix, but a related open PR aims to address OpenAPI schema generation issues, including problems with the `required` property placement ([source](https://github.com/better-auth/better-auth/pull/2107)). Until a fix is released, you can manually patch the generated OpenAPI schema in your app after generation to move the `required` array to the correct location. This manual patch approach is recommended in similar cases for other endpoints as well. If you need an example of how to patch the schema programmatically, let me know! <!-- 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/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/a302adc8-2b55-4406-a28a-9b6779180da4?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5607)
Author
Owner

@JohnCido commented on GitHub (Oct 27, 2025):

I have confirmed the root cause here: 97cd4a2059/packages/better-auth/src/plugins/email-otp/index.ts (L624)

@JohnCido commented on GitHub (Oct 27, 2025): I have confirmed the root cause here: https://github.com/better-auth/better-auth/blob/97cd4a205957002568915b2f8b85c2b9c8de76d9/packages/better-auth/src/plugins/email-otp/index.ts#L624
Author
Owner

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

Confirmed—the bug is caused by the required array being placed inside properties in the OpenAPI schema at that line in the email-otp plugin, which is not valid per the OpenAPI spec. The fix is to move required to be a sibling of properties at the object schema level, not nested inside it. If you need a quick workaround, you can patch the generated OpenAPI JSON after generation by moving the required array out of properties and into the parent object for this endpoint's response schema. Let me know if you want an example of how to do this programmatically.
Reference

To reply, just mention @dosu.


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

@dosubot[bot] commented on GitHub (Oct 27, 2025): <!-- Answer --> Confirmed—the bug is caused by the `required` array being placed inside `properties` in the OpenAPI schema at that line in the email-otp plugin, which is not valid per the OpenAPI spec. The fix is to move `required` to be a sibling of `properties` at the object schema level, not nested inside it. If you need a quick workaround, you can patch the generated OpenAPI JSON after generation by moving the `required` array out of `properties` and into the parent object for this endpoint's response schema. Let me know if you want an example of how to do this programmatically. [Reference](https://github.com/better-auth/better-auth/blob/97cd4a205957002568915b2f8b85c2b9c8de76d9/packages/better-auth/src/plugins/email-otp/index.ts) <!-- 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/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/d70856e1-2d17-4e25-8db6-8c4d60b3a95c?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5607)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2212