#11477·better-auth

Username signin endpoint not enforcing captchas

Author: 0mhxCreated Sep 29, 2026Updated Sep 29, 2026

Is this suited for github?

  • Yes, this is suited for github

Reproduction

  1. configure auth with the captcha and username plugin
  2. send a signin request to the username endpoint (/api/auth/sign-in/username) with only the username and password

Current vs. Expected behavior

currently it successfully creates a new login session, returning a session token (for a valid user). It should give a missing captcha response instead.

$ curl -i -X POST https://site/api/auth/sign-in/username -H 'Content-Type: application/json' -d '{"username":"...","password":"..."}'

HTTP/2 200 
content-type: application/json
access-control-expose-headers: set-auth-token
alt-svc: h3=":443"; ma=86400
server: cloudflare
set-auth-token: xxx
set-cookie: __Secure-indicia.session_token=Fxxx; Max-Age=604800; Path=/; HttpOnly; Secure; SameSite=Lax
{"redirect":false,"token":"xxx","user":{...}}

expected response

{"message":"Missing CAPTCHA response","code":"MISSING_RESPONSE"}

What version of Better Auth are you using?

1.7,1

System info

trimmed bcs of space limit

json
{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 ZEN SMP PREEMPT_DYNAMIC Mon, 14 Sep 2026 22:41:40 +0000",
    "release": "7.2.6-zen2-1-zen",
    "cpuCount": 16,
    "cpuModel": "AMD Ryzen 9 7940HS w/ Radeon 780M Graphics",
    "totalMemory": "14.84 GB",
    "freeMemory": "1.10 GB"
  },
  "node": {
    "version": "v24.18.0",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "9.4.0"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "1.7.1",
    "config": {
      "appName": "Indicia",
      "user": {
        "additionalFields": {
          "tokens": {
            "type": "number",
            "required": false,
            "defaultValue": 0,
            "input": false
          },
          "acceptedLegalHash": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": false
          },
          "taxState": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": true
          },
          "acceptOrgInvites": {
            "type": "boolean",
            "required": false,
            "defaultValue": false,
            "input": true
          },
          "restrictedFeatures": {
            "type": "string[]",
            "required": false,
            "defaultValue": [],
            "input": false
          },
          "restrictedModels": {
            "type": "string[]",
            "required": false,
            "defaultValue": [],
            "input": false
          },
          "stripeId": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": false
          },
          "flagged": {
            "type": "boolean",
            "required": false,
            "defaultValue": false,
            "input": false
          },
          "referralLink": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": false
          },
          "referred": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": false
          },
          "boughtCreditsAfterReferral": {
            "type": "boolean",
            "required": false,
            "defaultValue": null,
            "input": false
          },
          "lockedCredits": {
            "type": "number",
            "required": false,
            "defaultValue": 0,
            "input": false
          },
          "updatesLockedCredits": {
            "type": "number",
            "required": false,
            "defaultValue": 0,
            "input": false
          },
          "stripeConnectedId": {
            "type": "string",
            "required": false,
            "defaultValue": null,
            "input": false
          }
        },
        "deleteUser": {
          "enabled": true
        }
      },
      "hooks": {},
      "plugins": [
        {
          "name": "captcha",
          "config": {
            "id": "captcha",
            "version": "1.7.1",
            "$ERROR_CODES": {
              "VERIFICATION_FAILED": {
                "code": "VERIFICATION_FAILED",
                "message": "Captcha verification failed"
              },
              "MISSING_RESPONSE": {
                "code": "MISSING_RESPONSE",
                "message": "Missing CAPTCHA response"
              },
              "UNKNOWN_ERROR": {
                "code": "UNKNOWN_ERROR",
                "message": "Something went wrong"
              }
            },
            "options": {
              "provider": "cloudflare-turnstile"
            }
          }
        },
        {
          "name": "username",
          "config": {
            "id": "username",
            "version": "1.7.1",
            "endpoints": {},
            "schema": {
              "user": {
                "fields": {
                  "username": {
                    "type": "string",
                    "required": false,
                    "sortable": true,
                    "unique": true,
                    "returned": true,
                    "transform": {}
                  },
                  "displayUsername": {
                    "type": "string",
                    "required": false,
                    "transform": {}
                  }
                }
              }
            },
            "hooks": {
              "before": [
                {},
                {},
                {}
              ]
            },
            "options": {
              "minUsernameLength": 3,
              "maxUsernameLength": 24,
              "usernameNormalization": false
            },
            "$ERROR_CODES": {
              "INVALID_USERNAME_OR_PASSWORD": {
                "code": "INVALID_USERNAME_OR_PASSWORD",
                "message": "Invalid username or password"
              },
              "EMAIL_NOT_VERIFIED": {
                "code": "EMAIL_NOT_VERIFIED",
                "message": "Email not verified"
              },
              "UNEXPECTED_ERROR": {
                "code": "UNEXPECTED_ERROR",
                "message": "Unexpected error"
              },
              "USERNAME_IS_ALREADY_TAKEN": {
                "code": "USERNAME_IS_ALREADY_TAKEN",
                "message": "Username is already taken. Please try another."
              },
              "USERNAME_TOO_SHORT": {
                "code": "USERNAME_TOO_SHORT",
                "message": "Username is too short"
              },
              "USERNAME_TOO_LONG": {
                "code": "USERNAME_TOO_LONG",
                "message": "Username is too long"
              },
              "INVALID_USERNAME": {
                "code": "INVALID_USERNAME",
                "message": "Username is invalid"
              },
              "INVALID_DISPLAY_USERNAME": {
                "code": "INVALID_DISPLAY_USERNAME",
                "message": "Display username is invalid"
              },
              "USERNAME_IS_IMMUTABLE": {
                "code": "USERNAME_IS_IMMUTABLE",
                "message": "Username cannot be updated"
              }
            }
          }
        }
      ],
      "emailAndPassword": {
        "enabled": true,
        "autoSignIn": true,
        "requireEmailVerification": true,
        "autoSignInAfterVerification": true,
        "revokeSessionsOnPasswordReset": true
      },
      "emailVerification": {
        "sendOnSignUp": true,
        "sendOnSignIn": true,
        "autoSignInAfterVerification": true
      }
    }
  }
}

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

Backend

Auth config (if applicable)

typescript
betterAuth({
    baseURL: workerEnv.BETTER_AUTH_URL,
    plugins: [
      captcha({
        provider: 'cloudflare-turnstile',
        secretKey: workerEnv.TURNSTILE_SECRET,
      }),
      username({
        minUsernameLength: MIN_USERNAME_LENGTH,
        maxUsernameLength: 24,
        usernameValidator: isValidUsername,
        usernameNormalization: false,
      }),
    ],
    emailAndPassword: {
      enabled: true,
      autoSignIn: true,
      requireEmailVerification: true,
      autoSignInAfterVerification: true,
    },
  });

Additional context

No response