Ban User, userId check #1923

Closed
opened 2026-03-13 09:12:52 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @anmol-fzr on GitHub (Sep 14, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

As of now when the ban user api is hit, better-auth doesn't check if the user with userId exists or not.

The Server must return a 400 incase the user with userId doesn't exists which in latest version just returns 200

Current vs. Expected behavior

As of now when the ban user api is hit, better-auth doesn't check if the user with userId exists or not.

The Server must return a 400 incase the user with userId doesn't exists which in latest version just returns 200

What version of Better Auth are you using?

1.3.4

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Sun, 06 Jul 2025 11:14:36 +0000",
    "release": "6.15.5-arch1-1",
    "cpuCount": 16,
    "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P",
    "totalMemory": "23.17 GB",
    "freeMemory": "18.53 GB"
  },
  "node": {
    "version": "v20.19.3",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.2.21"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "0.0.0",
    "config": {
      "appName": "safe-fin-api",
      "session": {
        "cookieCache": {
          "enabled": true,
          "maxAge": 216000
        }
      },
      "plugins": [
        {
          "name": "expo",
          "config": {
            "id": "expo",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists",
              "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",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users"
            },
            "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
                  }
                }
              }
            },
            "options": {
              "adminUserIds": [
                "F7EOrNtgbhOUA4FYvj0r7bN4eJykYGMb"
              ]
            }
          }
        },
        {
          "name": "open-api",
          "config": {
            "id": "open-api",
            "endpoints": {}
          }
        },
        {
          "name": "multi-session",
          "config": {
            "id": "multi-session",
            "endpoints": {},
            "hooks": {
              "after": [
                {},
                {}
              ]
            },
            "$ERROR_CODES": {
              "INVALID_SESSION_TOKEN": "[REDACTED]"
            }
          }
        },
        {
          "name": "phone-number",
          "config": {
            "id": "phone-number",
            "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",
              "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"
            }
          }
        }
      ],
      "baseURL": "http://localhost:8787",
      "secret": "[REDACTED]",
      "trustedOrigins": [
        "http://localhost:5173",
        "http://192.168.29.57:5173"
      ]
    }
  }
}

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

Backend

Auth config (if applicable)

/**
 * Better Auth CLI configuration file
 *
 * Docs: https://www.better-auth.com/docs/concepts/cli
 */
import { betterAuth } from "better-auth";
import { betterAuthOptions } from "./src/better-auth/options";
import { envs } from "./src/envs";
import { createClient } from "@libsql/client";

import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/libsql";

const { BETTER_AUTH, DB, CORS_URL } = envs;

type GetDbParams = {
	TURSO_DB_URL: string;
	TURSO_DB_TOKEN: string;
};

function getDb(envs: GetDbParams): ReturnType<typeof drizzle> {
	console.log("getDB", envs);

	const turso = createClient({
		url: envs.TURSO_DB_URL,
		authToken: envs.TURSO_DB_TOKEN,
	});

	return drizzle(turso);
}

const getAuthDrizzleAdapter = (env: Parameters<typeof getDb>[0]) => {
	const db = getDb(env);
	return drizzleAdapter(db, { provider: "sqlite" });
};

const database = getAuthDrizzleAdapter({
	TURSO_DB_URL: DB.URL,
	TURSO_DB_TOKEN: DB.TOKEN,
});

export const auth: ReturnType<typeof betterAuth> = betterAuth({
	...betterAuthOptions,
	database,
	baseURL: BETTER_AUTH.URL,
	secret: BETTER_AUTH.SECRET,
	trustedOrigins: [CORS_URL, "http://192.168.29.57:5173"],
});

Additional context

No response

Originally created by @anmol-fzr on GitHub (Sep 14, 2025). ### Is this suited for github? - [ ] Yes, this is suited for github ### To Reproduce As of now when the ban user api is hit, better-auth doesn't check if the user with userId exists or not. The Server must return a 400 incase the user with userId doesn't exists which in latest version just returns 200 ### Current vs. Expected behavior As of now when the ban user api is hit, better-auth doesn't check if the user with userId exists or not. The Server must return a 400 incase the user with userId doesn't exists which in latest version just returns 200 ### What version of Better Auth are you using? 1.3.4 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Sun, 06 Jul 2025 11:14:36 +0000", "release": "6.15.5-arch1-1", "cpuCount": 16, "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P", "totalMemory": "23.17 GB", "freeMemory": "18.53 GB" }, "node": { "version": "v20.19.3", "env": "development" }, "packageManager": { "name": "bun", "version": "1.2.21" }, "frameworks": null, "databases": null, "betterAuth": { "version": "0.0.0", "config": { "appName": "safe-fin-api", "session": { "cookieCache": { "enabled": true, "maxAge": 216000 } }, "plugins": [ { "name": "expo", "config": { "id": "expo", "hooks": { "after": [ {} ] } } }, { "name": "admin", "config": { "id": "admin", "hooks": { "after": [ {} ] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists", "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", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users" }, "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 } } } }, "options": { "adminUserIds": [ "F7EOrNtgbhOUA4FYvj0r7bN4eJykYGMb" ] } } }, { "name": "open-api", "config": { "id": "open-api", "endpoints": {} } }, { "name": "multi-session", "config": { "id": "multi-session", "endpoints": {}, "hooks": { "after": [ {}, {} ] }, "$ERROR_CODES": { "INVALID_SESSION_TOKEN": "[REDACTED]" } } }, { "name": "phone-number", "config": { "id": "phone-number", "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", "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" } } } ], "baseURL": "http://localhost:8787", "secret": "[REDACTED]", "trustedOrigins": [ "http://localhost:5173", "http://192.168.29.57:5173" ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript /** * Better Auth CLI configuration file * * Docs: https://www.better-auth.com/docs/concepts/cli */ import { betterAuth } from "better-auth"; import { betterAuthOptions } from "./src/better-auth/options"; import { envs } from "./src/envs"; import { createClient } from "@libsql/client"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { drizzle } from "drizzle-orm/libsql"; const { BETTER_AUTH, DB, CORS_URL } = envs; type GetDbParams = { TURSO_DB_URL: string; TURSO_DB_TOKEN: string; }; function getDb(envs: GetDbParams): ReturnType<typeof drizzle> { console.log("getDB", envs); const turso = createClient({ url: envs.TURSO_DB_URL, authToken: envs.TURSO_DB_TOKEN, }); return drizzle(turso); } const getAuthDrizzleAdapter = (env: Parameters<typeof getDb>[0]) => { const db = getDb(env); return drizzleAdapter(db, { provider: "sqlite" }); }; const database = getAuthDrizzleAdapter({ TURSO_DB_URL: DB.URL, TURSO_DB_TOKEN: DB.TOKEN, }); export const auth: ReturnType<typeof betterAuth> = betterAuth({ ...betterAuthOptions, database, baseURL: BETTER_AUTH.URL, secret: BETTER_AUTH.SECRET, trustedOrigins: [CORS_URL, "http://192.168.29.57:5173"], }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 09:12:52 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Sep 14, 2025):

This is suited for GitHub—it's a clear backend bug/feature gap.

The current ban user API in Better Auth v1.3.4 does not check if the userId exists before attempting to ban. If the user doesn't exist, it still returns a 200 response with a null user object. This is inconsistent with other admin endpoints (like get user), which do check for existence and return a 404 error if the user is not found. The API should explicitly check for user existence and return a 400 or 404 error when the userId does not exist, to align with expected RESTful behavior and other endpoints in the framework. You can see how the get user endpoint handles this in PR #2587.

For now, if you want to patch this, you can add a user existence check using the internal adapter's findUserById before calling updateUser in the ban user endpoint, and throw an error if the user is not found.

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 (Sep 14, 2025): <!-- Answer --> This is suited for GitHub—it's a clear backend bug/feature gap. The current ban user API in Better Auth v1.3.4 does not check if the userId exists before attempting to ban. If the user doesn't exist, it still returns a 200 response with a null user object. This is inconsistent with other admin endpoints (like get user), which do check for existence and return a 404 error if the user is not found. The API should explicitly check for user existence and return a 400 or 404 error when the userId does not exist, to align with expected RESTful behavior and other endpoints in the framework. You can see how the get user endpoint handles this in [PR #2587](https://github.com/better-auth/better-auth/pull/2587). For now, if you want to patch this, you can add a user existence check using the internal adapter's `findUserById` before calling `updateUser` in the ban user endpoint, and throw an error if the user is not found. <!-- 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/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/13d9740d-a966-4869-be6a-1a6d9f310206?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/4648)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1923