@dupecom/botcha-验证
用于 BOTCHA JWT 令牌的服务器端验证中间软件.
安装
npm install @dupecom/botcha-verify
# or
yarn add @dupecom/botcha-verify
# or
bun add @dupecom/botcha-verify
特征
- JWKS核查(ES256) ——不需要共享秘密,密钥自动旋转
- HS256 共同秘密核查(遗产,仍得到支持)
- 自动检查过期
- 观众索赔的确认
- 发行人验证( I)
botcha.aiJWKS 模式 - 客户端 IP 绑定支持
- 托肯撤销检查( 可选)
- 快速和 Hono 中间软件
- 带有完整类型定义的脚本类型支持
- 自定义错误处理器
使用量
JWKS 核查(建议)
推荐的方法从JWKS端取出BOTCHA的公钥. 没有共享的机密管理——密钥旋转自动处理.
import { verifyBotchaToken } from '@dupecom/botcha-verify';
const result = await verifyBotchaToken(token, {
jwksUrl: 'https://botcha.ai/.well-known/jwks',
audience: 'https://api.example.com',
});
if (result.valid) {
console.log('Token valid! Challenge:', result.payload.sub);
console.log('Solve time:', result.payload.solveTime, 'ms');
} else {
console.error('Token invalid:', result.error);
}
遗产:共享秘密核查
仍然支持使用HS256令牌的现有整合.
import { verifyBotchaToken } from '@dupecom/botcha-verify';
const result = await verifyBotchaToken(token, {
secret: process.env.BOTCHA_SECRET!,
audience: 'https://api.example.com',
requireIp: true,
});
表达式中件
import express from 'express';
import { botchaVerify } from '@dupecom/botcha-verify/express';
const app = express();
// RECOMMENDED: JWKS verification
app.use('/api', botchaVerify({
jwksUrl: 'https://botcha.ai/.well-known/jwks',
audience: 'https://api.example.com',
}));
// LEGACY: Shared secret
app.use('/api', botchaVerify({
secret: process.env.BOTCHA_SECRET!,
audience: 'https://api.example.com',
requireIp: true,
}));
app.get('/api/protected', (req, res) => {
console.log('Challenge ID:', req.botcha?.sub);
console.log('Solve time:', req.botcha?.solveTime);
res.json({ message: 'Success' });
});
Hono 中间软件
import { Hono } from 'hono';
import { botchaVerify } from '@dupecom/botcha-verify/hono';
import type { BotchaTokenPayload } from '@dupecom/botcha-verify';
const app = new Hono<{ Variables: { botcha: BotchaTokenPayload } }>();
// RECOMMENDED: JWKS verification
app.use('/api/*', botchaVerify({
jwksUrl: 'https://botcha.ai/.well-known/jwks',
audience: 'https://api.example.com',
}));
// LEGACY: Shared secret
app.use('/api/*', botchaVerify({
secret: env.BOTCHA_SECRET,
audience: 'https://api.example.com',
requireIp: true,
}));
app.get('/api/protected', (c) => {
const botcha = c.get('botcha');
console.log('Challenge ID:', botcha.sub);
console.log('Solve time:', botcha.solveTime);
return c.json({ message: 'Success' });
});
API 密码
verifyBotchaToken(token, options, clientIp?)
检查一个BOTCHA JWT标志.
参数:
token(字符串):JWT验证符options(BotchaVrify options):核查选项(至少其中一种)secret或者说jwksUrl(所需)clientIp(弦,可选): 用于验证的客户端 IP
回返情况: Promise<VerificationResult>
interface VerificationResult {
valid: boolean;
payload?: BotchaTokenPayload;
error?: string;
}
BotchaVerifyOptions
interface BotchaVerifyOptions {
// JWKS URL for ES256 verification (recommended)
jwksUrl?: string;
// Cache JWKS keys for this many seconds (default: 3600)
jwksCacheTtl?: number;
// JWT secret for HS256 verification (legacy)
secret?: string;
// At least one of `secret` or `jwksUrl` must be provided.
// If both are provided, JWKS is tried first, falling back to secret.
// Optional: Expected audience claim
audience?: string;
// Optional: Validate client IP claim
requireIp?: boolean;
// Optional: Custom error handler
onError?: (error: string, context: VerificationContext) => void | Promise<void>;
// Optional: Token revocation check
checkRevocation?: (jti: string) => Promise<boolean>;
}
BotchaTokenPayload
interface BotchaTokenPayload {
sub: string; // Challenge ID
iat: number; // Issued at
exp: number; // Expires at
jti: string; // JWT ID
type: 'botcha-verified';
solveTime: number; // Solve time in ms
aud?: string; // Optional audience
client_ip?: string; // Optional client IP
}
托肯验证
核查人检查:
- 签署:ES256通过JWKS(推荐)或HS256通过共享秘密(遗产)
- 过期: 切入不能过期
- 类型: 托肯必须是
botcha-verified(无)botcha-refresh(中文(简体) ) - 发行人 (JWKS模式):托肯
iss必须是botcha.ai - 观众 (可选):托肯
aud必须与预期受众匹配 - 客户端IP (可选):托肯
client_ip必须匹配请求 IP - 撤销 (可选) : Token JTI 不可撤销
从共享机密向JWKS的迁移
替换 secret 与 jwksUrl 在您的配置中。 过渡时期
您可以同时提供 —— JWKS 被先尝试后退至秘密 :
// Transition: both methods supported
app.use('/api', botchaVerify({
jwksUrl: 'https://botcha.ai/.well-known/jwks',
secret: process.env.BOTCHA_SECRET!, // fallback during migration
audience: 'https://api.example.com',
}));
// After migration: JWKS only
app.use('/api', botchaVerify({
jwksUrl: 'https://botcha.ai/.well-known/jwks',
audience: 'https://api.example.com',
}));
自定义错误处理
app.use('/api', botchaVerify({
jwksUrl: 'https://botcha.ai/.well-known/jwks',
onError: (error, context) => {
console.error('Token verification failed:', error);
console.error('Context:', context);
},
}));
Token 撤销
执行自定义撤销检查 :
import { verifyBotchaToken } from '@dupecom/botcha-verify';
const result = await verifyBotchaToken(token, {
jwksUrl: 'https://botcha.ai/.well-known/jwks',
checkRevocation: async (jti) => {
const isRevoked = await db.revokedTokens.exists(jti);
return isRevoked;
},
});
客户IP提取器
中间软件自动从 :
- 云雾花数字 :
CF-Connecting-IP标题 - 代理数字 :
X-Forwarded-For页眉( 第一个 IP) - 装入平衡器数字 :
X-Real-IP标题 - 直接数字 :
req.ip(出)或倒(呼诺)
安全说明
- 犹太人: 公共密钥被缓存并自动旋转
jose图书馆 - 未打开: 如果检查出错, 撤销检查失败打开
- IP 验证: 仅在
requireIp: true设定 - 观众: 强烈建议部署多API
- 发行人: 自动验证为
botcha.ai在 JWKS 模式下
许可证
麻省理工学院