better-auth
Version:
The most comprehensive authentication framework for TypeScript.
96 lines (94 loc) • 3.74 kB
JavaScript
import { mergeSchema } from "../../db/schema.mjs";
import { APIError } from "../../api/index.mjs";
import { defaultRoles } from "./access/statement.mjs";
import "./access/index.mjs";
import { getEndpointResponse } from "../../utils/plugin-helper.mjs";
import { ADMIN_ERROR_CODES } from "./error-codes.mjs";
import { adminUpdateUser, banUser, createUser, getUser, impersonateUser, listUserSessions, listUsers, removeUser, revokeUserSession, revokeUserSessions, setRole, setUserPassword, stopImpersonating, unbanUser, userHasPermission } from "./routes.mjs";
import { schema } from "./schema.mjs";
import { BetterAuthError } from "@better-auth/core/error";
import { createAuthMiddleware } from "@better-auth/core/api";
//#region src/plugins/admin/admin.ts
const admin = (options) => {
const opts = {
defaultRole: options?.defaultRole ?? "user",
adminRoles: options?.adminRoles ?? ["admin"],
bannedUserMessage: options?.bannedUserMessage ?? "You have been banned from this application. Please contact support if you believe this is an error.",
...options
};
if (options?.adminRoles) {
const invalidRoles = (Array.isArray(options.adminRoles) ? options.adminRoles : [...options.adminRoles.split(",")]).filter((role) => !Object.keys(options?.roles || defaultRoles).map((r) => r.toLowerCase()).includes(role.toLowerCase()));
if (invalidRoles.length > 0) throw new BetterAuthError(`Invalid admin roles: ${invalidRoles.join(", ")}. Admin roles must be defined in the 'roles' configuration.`);
}
return {
id: "admin",
init() {
return { options: { databaseHooks: {
user: { create: { async before(user) {
return { data: {
role: options?.defaultRole ?? "user",
...user
} };
} } },
session: { create: { async before(session, ctx) {
if (!ctx) return;
const user = await ctx.context.internalAdapter.findUserById(session.userId);
if (user.banned) {
if (user.banExpires && new Date(user.banExpires).getTime() < Date.now()) {
await ctx.context.internalAdapter.updateUser(session.userId, {
banned: false,
banReason: null,
banExpires: null
});
return;
}
if (ctx && (ctx.path.startsWith("/callback") || ctx.path.startsWith("/oauth2/callback"))) {
const redirectURI = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
throw ctx.redirect(`${redirectURI}?error=banned&error_description=${opts.bannedUserMessage}`);
}
throw new APIError("FORBIDDEN", {
message: opts.bannedUserMessage,
code: "BANNED_USER"
});
}
} } }
} } };
},
hooks: { after: [{
matcher(context) {
return context.path === "/list-sessions";
},
handler: createAuthMiddleware(async (ctx) => {
const response = await getEndpointResponse(ctx);
if (!response) return;
const newJson = response.filter((session) => {
return !session.impersonatedBy;
});
return ctx.json(newJson);
})
}] },
endpoints: {
setRole: setRole(opts),
getUser: getUser(opts),
createUser: createUser(opts),
adminUpdateUser: adminUpdateUser(opts),
listUsers: listUsers(opts),
listUserSessions: listUserSessions(opts),
unbanUser: unbanUser(opts),
banUser: banUser(opts),
impersonateUser: impersonateUser(opts),
stopImpersonating: stopImpersonating(),
revokeUserSession: revokeUserSession(opts),
revokeUserSessions: revokeUserSessions(opts),
removeUser: removeUser(opts),
setUserPassword: setUserPassword(opts),
userHasPermission: userHasPermission(opts)
},
$ERROR_CODES: ADMIN_ERROR_CODES,
schema: mergeSchema(schema, opts.schema),
options
};
};
//#endregion
export { admin };
//# sourceMappingURL=admin.mjs.map