Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计异常

bknd-password-resetbknd 密码重置

Agent Skill

bknd-password-reset 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

324

周安装

13

GitHub Stars

3

下载量

105
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bknd-password-reset(bknd 密码重置)
来源仓库:https://github.com/cameronapak/bknd-skills
仓库路径:skills/bknd-password-reset
安装命令:
npx skills add https://github.com/cameronapak/bknd-skills --skill bknd-password-reset
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/cameronapak/bknd-skills --skill bknd-password-reset

简介

用于实现密码重置和修改功能,支持管理员后台操作。

  • 不提供内置忘记密码流程,需自行实现令牌生成与邮件发送。
  • 适用于服务端密码变更和验证逻辑编写。
  • 需启用认证系统并配置邮件发送能力。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。
  • bknd-password-reset 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Password Reset Flow

Implement password reset and change functionality in Bknd applications.

Prerequisites

  • Bknd project with auth enabled (bknd-setup-auth)
  • Password strategy configured
  • For email-based reset: email sending capability (external service)

Important Context

Bknd provides:

  • Server-side changePassword() method for admin/system password changes
  • No built-in forgot-password flow - you must implement token generation, email sending, and validation

When to Use UI Mode

  • Admin-initiated password resets via admin panel

UI steps: Admin Panel > Data > users > Select user > Edit

Note: Direct password editing via UI sets raw value - use server-side method for proper hashing.

When to Use Code Mode

  • Implementing forgot-password flow with email
  • Adding change-password functionality for logged-in users
  • Admin tools for password resets

Server-Side Password Change

Using changePassword() Method

import { serve } from "bknd/adapter/node";
import { defineConfig } from "bknd";

export default serve(
  defineConfig({ /* config */ }),
  {
    async seed(ctx) {
      // Change password by user ID
      await ctx.app.module.auth.changePassword(1, "newSecurePassword123");

      // Or find user first
      const { data: user } = await ctx.em.repo("users").findOne({
        email: "user@example.com",
      });
      if (user) {
        await ctx.app.module.auth.changePassword(user.id, "newPassword456");
      }
    },
  }
);

Method signature:

changePassword(userId: number | string, newPassword: string): Promise<boolean>

Constraints:

  • User must exist
  • User must use password strategy (not OAuth)
  • Password is automatically hashed using configured hashing method

Building Forgot-Password Flow

Since Bknd doesn't have built-in forgot-password, implement a custom flow:

Step 1: Create Reset Token Entity

import { em, entity, text, date, number } from "bknd";

const schema = em({
  password_resets: entity("password_resets", {
    email: text().required(),
    token: text().required().unique(),
    expires_at: date().required(),
    used: number().default(0), // 0 = unused, 1 = used
  }),
});

Step 2: Request Reset Endpoint

import { randomBytes } from "crypto";

async function requestPasswordReset(email: string, ctx: any) {
  const api = ctx.api;

  // Check if user exists (don't reveal in response)
  const { data: user } = await api.data.readOneBy("users", { email });
  if (!user) {
    return { success: true, message: "If email exists, reset link sent" };
  }

  // Generate secure token
  const token = randomBytes(32).toString("hex");
  const expiresAt = new Date(Date.now() + 60 * 60 * 1000); // 1 hour

  // Store reset token
  await api.data.createOne("password_resets", {
    email,
    token,
    expires_at: expiresAt.toISOString(),
    used: 0,
  });

  // Send email (use your email service: SendGrid, Resend, etc.)
  const resetUrl = `https://yourapp.com/reset-password?token=${token}`;
  // await emailService.send({ to: email, subject: "Password Reset", ... });

  return { success: true, message: "If email exists, reset link sent" };
}

Step 3: Validate and Reset Password

async function resetPassword(token: string, newPassword: string, ctx: any) {
  const api = ctx.api;
  const auth = ctx.app.module.auth;

  // Find valid token
  const { data: resetRecord } = await api.data.readOneBy("password_resets", {
    token,
    used: 0,
  });

  if (!resetRecord) {
    throw new Error("Invalid or expired reset token");
  }

  // Check expiration
  if (new Date(resetRecord.expires_at) < new Date()) {
    throw new Error("Reset token has expired");
  }

  // Find user
  const { data: user } = await api.data.readOneBy("users", {
    email: resetRecord.email,
  });
  if (!user) {
    throw new Error("User not found");
  }

  // Change password (properly hashed)
  await auth.changePassword(user.id, newPassword);

  // Mark token as used
  await api.data.updateOne("password_resets", resetRecord.id, { used: 1 });

  return { success: true };
}

Step 4: React Frontend

Request Reset Form:

function ForgotPasswordForm() {
  const [email, setEmail] = useState("");
  const [status, setStatus] = useState<"idle" | "loading" | "sent">("idle");

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setStatus("loading");

    await fetch("/api/password-reset/request", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email }),
    });
    setStatus("sent");
  }

  if (status === "sent") {
    return <p>Check your email for reset instructions.</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
        required
      />
      <button type="submit" disabled={status === "loading"}>
        {status === "loading" ? "Sending..." : "Send Reset Link"}
      </button>
    </form>
  );
}

Reset Password Form:

function ResetPasswordForm() {
  const [searchParams] = useSearchParams();
  const navigate = useNavigate();
  const token = searchParams.get("token");

  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [error, setError] = useState("");

  if (!token) return <p>Invalid reset link.</p>;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (password !== confirmPassword) {
      setError("Passwords do not match");
      return;
    }

    const res = await fetch("/api/password-reset/confirm", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ token, password }),
    });

    if (res.ok) {
      navigate("/login");
    } else {
      const data = await res.json();
      setError(data.message || "Reset failed");
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <p className="error">{error}</p>}
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="New Password"
        minLength={8}
        required
      />
      <input
        type="password"
        value={confirmPassword}
        onChange={(e) => setConfirmPassword(e.target.value)}
        placeholder="Confirm Password"
        required
      />
      <button type="submit">Reset Password</button>
    </form>
  );
}

Authenticated Password Change

For logged-in users changing their own password:

async function changePassword(currentPassword: string, newPassword: string) {
  const api = new Api({ host: "http://localhost:7654", storage: localStorage });

  // Verify current password by re-authenticating
  const { data: userData } = await api.auth.me();
  if (!userData?.user) throw new Error("Not authenticated");

  const { ok } = await api.auth.login("password", {
    email: userData.user.email,
    password: currentPassword,
  });

  if (!ok) throw new Error("Current password is incorrect");

  // Call custom password change endpoint
  const res = await fetch("/api/password-change", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ newPassword }),
  });

  if (!res.ok) throw new Error("Failed to change password");
}

Security Considerations

Token Security

// Good: Cryptographically secure token
import { randomBytes } from "crypto";
const token = randomBytes(32).toString("hex"); // 64 chars

// Bad: Predictable token
const token = Math.random().toString(36); // NOT secure!

Rate Limiting

const resetAttempts = new Map<string, { count: number; lastAttempt: Date }>();

function checkRateLimit(email: string): boolean {
  const record = resetAttempts.get(email);
  const now = new Date();

  if (!record || record.lastAttempt < new Date(now.getTime() - 3600000)) {
    resetAttempts.set(email, { count: 1, lastAttempt: now });
    return true;
  }

  if (record.count >= 3) return false; // Max 3 per hour

  record.count++;
  return true;
}

Common Pitfalls

Not Hashing Password

// Wrong - bypasses hashing
await api.data.updateOne("users", userId, {
  strategy_value: "plainPassword123",
});

// Correct - uses configured hashing
await ctx.app.module.auth.changePassword(userId, "plainPassword123");

Email Enumeration

// Wrong - reveals email existence
if (!user) return { error: "Email not found" };

// Correct - doesn't reveal
return { success: true, message: "If email exists, reset link sent" };

OAuth User Password Reset

const { data: user } = await api.data.readOneBy("users", { email });
if (user?.strategy !== "password") {
  return { error: "This account uses social login" };
}

Verification

# 1. Request reset
curl -X POST http://localhost:7654/api/password-reset/request \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

# 2. Reset password (use token from email/DB)
curl -X POST http://localhost:7654/api/password-reset/confirm \
  -H "Content-Type: application/json" \
  -d '{"token": "<token>", "password": "newPassword123"}'

# 3. Login with new password
curl -X POST http://localhost:7654/api/auth/password/login \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "newPassword123"}'

DOs and DON'Ts

DO:

  • Use changePassword() method for proper hashing
  • Generate cryptographically secure tokens
  • Set short expiration (1 hour max)
  • Mark tokens as used immediately
  • Return consistent responses (don't reveal email existence)
  • Rate limit reset requests

DON'T:

  • Store/transmit passwords in plain text
  • Use predictable tokens (Math.random)
  • Allow unlimited reset attempts
  • Keep tokens valid indefinitely
  • Allow password reset for OAuth users

Related Skills

  • bknd-setup-auth - Configure authentication system
  • bknd-login-flow - Login/logout functionality
  • bknd-registration - User registration setup
  • bknd-session-handling - Manage user sessions
  • bknd-custom-endpoint - Create custom API endpoints

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.32%
按下载量换算35

Claude

32.99%
按下载量换算35

Cursor

19.91%
按下载量换算21

Gemini CLI

10.09%
按下载量换算11

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills