npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

better-auth-my-admin

v0.1.0

Published

A flexible RBAC admin plugin for Better Auth with complete control inversion.

Readme

Better Auth My Admin

[!CAUTION] Total Control, Total Responsibility

This plugin implements Control Inversion for permissions. Unlike the official admin plugin, it makes ZERO assumptions about your role system.

You simply provide a checkPermission callback, and the plugin delegates all authorization decisions to it. You are solely responsible for ensuring your permission logic is secure and handles all edge cases.

Features

  • 🛠 Complete Control Inversion - You define checkPermission logic.
  • ⚡️ Zero Assumption - Doesn't enforce specific roles or database schemas for permissions.
  • 🌍 Localization Support - Compatible with better-auth-localization for internationalization.
  • 🔒 Secure Defaults - Handles user banning, session revocation, and password management securely.
  • 📦 Type Safe - Fully typed with TypeScript.

Installation

npm install better-auth-my-admin
# or
pnpm add better-auth-my-admin
# or
yarn add better-auth-my-admin

Setup

1. Add the plugin to your auth config

// auth.ts
import { betterAuth } from "better-auth";
import { myAdminPlugin } from "better-auth-my-admin";

export const auth = betterAuth({
  // ... other config
  plugins: [
    myAdminPlugin({
      // Define your permission logic here
      checkPermission: async ({ action }, ctx) => {
        const session = ctx.session;
        if (!session) return false;

        // Example: Only allow 'admin' role
        if (session.user.role === 'admin') return true;
        
        // Example: Allow specific action
        if (action === "ban-user" && session.user.isSuperAdmin) return true;

        // Return false to deny (triggers 403)
        return false;
      }
    })
  ]
});

2. Update Database Schema

Run the migration or generate the schema to add the necessary fields and tables to the database.

npx @better-auth/cli migrate

or

npx @better-auth/cli generate

This plugin adds the following fields to the user table:

| Field Name | Type | Description | | :--- | :--- | :--- | | banned | Boolean | Indicates whether the user is banned. | | banReason | String | The reason for the user's ban. | | banExpires | DateTime | The date when the user's ban will expire. |

3. Add the client plugin

import { createAuthClient } from "better-auth/react";
import { myAdminClient } from "better-auth-my-admin";

const authClient = createAuthClient({
  plugins: [myAdminClient()]
});

Usage

Client Side

You can use the myAdmin property on the auth client to perform admin actions. The client is fully typed.

await authClient.myAdmin.banUser({
    userId: "target-user-id",
    banReason: "Violation of terms"
});

Server Side

You can also call admin actions directly from your server-side code (e.g. in API routes or Server Actions) using auth.api.

Note: When calling from the server, you must pass the request headers to ensure the session context is correctly resolved.

import { auth } from "@/lib/auth"; // Your auth instance
import { headers } from "next/headers"; // Example for Next.js

await auth.api.banUser({
    body: {
        userId: "target-user-id",
        banReason: "Violation of terms"
    },
    headers: await headers()
});

API Reference

Set User Password

Changes the password of a user.

  • Path: /my-admin/set-user-password
  • Method: POST

Parameters

type setUserPassword = {
    /**
     * The user id which you want to set the password for.
     */
    userId: string;
    /**
     * The new password.
     */
    newPassword: string;
}

Examples

Client

await authClient.myAdmin.setUserPassword({
    userId: 'user-id',
    newPassword: 'new-password'
});

Server

await auth.api.setUserPassword({
    body: {
        userId: 'user-id',
        newPassword: 'new-password'
    },
    headers: await headers()
});

Ban User

Bans a user, preventing them from signing in and revokes all of their existing sessions.

  • Path: /my-admin/ban-user
  • Method: POST

Parameters

type banUser = {
    /**
     * The user id which you want to ban.
     */
    userId: string;
    /**
     * The reason for the ban.
     */
    banReason?: string;
    /**
     * The number of seconds until the ban expires. If not provided, the ban will never expire.
     */
    banExpiresIn?: number;
}

Examples

Client

await authClient.myAdmin.banUser({
    userId: 'user-id',
    banReason: 'Spamming',
    banExpiresIn: 604800 // 1 week
});

Server

await auth.api.banUser({
    body: {
        userId: 'user-id',
        banReason: 'Spamming'
    },
    headers: await headers()
});

Unban User

Removes the ban from a user, allowing them to sign in again.

  • Path: /my-admin/unban-user
  • Method: POST

Parameters

type unbanUser = {
    /**
     * The user id which you want to unban.
     */
    userId: string;
}

Examples

Client

await authClient.myAdmin.unbanUser({
    userId: 'user-id'
});

Server

await auth.api.unbanUser({
    body: { userId: 'user-id' },
    headers: await headers()
});

List User Sessions

Lists all active sessions for a specific user.

  • Path: /my-admin/list-user-sessions
  • Method: POST

Parameters

type listUserSessions = {
    /**
     * The user id to list sessions for.
     */
    userId: string;
}

Examples

Client

const { data } = await authClient.myAdmin.listUserSessions({
    userId: 'user-id'
});

Server

const sessions = await auth.api.listUserSessions({
    body: { userId: 'user-id' },
    headers: await headers()
});

Revoke User Session

Revokes a specific session for a user.

  • Path: /my-admin/revoke-user-session
  • Method: POST

Parameters

type revokeUserSession = {
    /**
     * The session token which you want to revoke.
     */
    sessionToken: string;
}

Examples

Client

await authClient.myAdmin.revokeUserSession({
    sessionToken: 'session-token'
});

Server

await auth.api.revokeUserSession({
    body: { sessionToken: 'session-token' },
    headers: await headers()
});

Revoke User Sessions

Revokes all sessions for a user.

  • Path: /my-admin/revoke-user-sessions
  • Method: POST

Parameters

type revokeUserSessions = {
    /**
     * The user id which you want to revoke all sessions for.
     */
    userId: string;
}

Examples

Client

await authClient.myAdmin.revokeUserSessions({
    userId: 'user-id'
});

Server

await auth.api.revokeUserSessions({
    body: { userId: 'user-id' },
    headers: await headers()
});

Localization

To translate error messages (e.g. to Chinese), use better-auth-localization:

localization({
  translations: {
    "zh-Hans": {
        "You are not allowed to perform this action": "禁止操作:您没有执行此操作的权限",
        "User not found": "用户不存在",
        "User is banned": "该用户已被封禁",
        "You cannot ban yourself": "您不能封禁自己",
        "Failed to update user": "更新用户信息失败",
        "Password is too short": "密码太短",
        "Password is too long": "密码太长"
    }
  }
})

License

MIT