@ activescott/ auth- 提供者 - sms
短消息的一次性代码提供者 @activescott/auth。用户输入他们的手机号码,得到6位数代码的短信,并按类型(或自动填充)签名.
这个软件包 无供应商依赖关系 ——快递作为交通工具注入. 使用供应商包或写自己的:
@activescott/auth-sms-twilio- 特维利奥:TwilioMessagingTransport(SMS,或RCS通过信使服务)和TwilioVerifyTransport(Twilio验证)ConsoleTransport(包括)——将代码打印到服务器控制台进行开发- 自定义: 已执行
SmsTransport { sendMessage(to, message): Promise<boolean> }。在 PR 第37号 实施和单位测试但未经核实的AWS账户;如果想要AWS并且可以测试结束,可以自由地接管该PR(36号 (有核对表).
两种运输
SmsTransport | VerificationTransport | |
|---|---|---|
| 谁做代码 | 此软件包 | 供应商 |
| 谁检查代码 | 此软件包 | 供应商 |
| 美国A2P 10DLC注册 | 交给你了 ——通过 " 运动登记册 " 开展品牌+运动,日-周加月费 | 无 - 供应商从已登记的发送者发送 |
| 每次登录的费用(美国) | 每简讯~0.011-0.013美元 | ~ 0.058美元(Twilio验证:每成功0.05美元+频道费) |
| 信件文本、 代码长度、 WebOTP 行 | | 卖家 |
SmsProvider 要么接受,要么接受。 路由,请求机构,饼干绑定,滥用检查,以及错误反应是完全相同的,因此切换是构造时的一行变化:
new SmsProvider({ appName: "MyApp" }, new TwilioVerifyTransport({ ... }))
选择 VerificationTransport 当10DLC的注册是你们和航运之间的事时——低注册量的固定月费往往会超过整个核实账单。 选择 SmsTransport 当音量使每个消息的价格占据主导地位时,或者您想要对消息文本的控制.
使用量
import { Auth, InMemoryChallengeStore } from "@activescott/auth"
import { SmsProvider, ConsoleTransport } from "@activescott/auth-provider-sms"
import { TwilioMessagingTransport } from "@activescott/auth-sms-twilio"
const auth = new Auth({
session: { secret: process.env.JWT_SECRET! /* ... */ },
userStore,
identityStore,
challengeStore: new InMemoryChallengeStore(), // DB-backed in production
providers: [
new SmsProvider(
{ appName: "MyApp", webOtpDomain: "myapp.example" },
process.env.NODE_ENV === "production"
? new TwilioMessagingTransport({
accountSid: process.env.TWILIO_ACCOUNT_SID!,
authToken: process.env.TWILIO_AUTH_TOKEN!,
messagingServiceSid: process.env.TWILIO_SMS_MESSAGING_SERVICE_SID,
})
: new ConsoleTransport(),
),
],
})
登录表单将电话号码张贴到 /auth/sms/initiate (提供商将代码发去文本,设置一个 Http 单向挑战 cookie,并用 ?sent=1); 代码表 /auth/sms/verify。一个可运行的应用程序显示全流 examples/react-router数字 :
<form method="post" action="/auth/sms/initiate">
<input name="phone" type="tel" autocomplete="tel" required />
<button>Text me a code</button>
</form>
<form method="post" action="/auth/sms/verify">
<input
name="code"
autocomplete="one-time-code"
inputmode="numeric"
pattern="[0-9]{6}"
required
/>
<button>Sign in</button>
</form>
配置
| 选项 | 默认 | 说明 |
|---|---|---|
appName | "App" | 在默认信件文本中显示 |
expiry | "10m" | 代码寿命( O)"30s", (中文(简体) ), "10m", (中文(简体) ), "1h", (...) (中文(简体) ) |
webOtpDomain | (关闭) | 附加 网络OTP 线条 @domain #code android/Chrome 单塔自动填充 |
messageTemplate | 内置 | (code, appName) => string 以自定义文本 |
otp.length | 6 | 代码中的数字 |
otp.maxAttempts | 5 | 质疑无效前的错误猜测( E)RATE_LIMITED(中文(简体) ) |
otp.cookieName | "auth_sms_challenge" | 挑战饼干名称 |
与一个 VerificationTransport 卖主负责写信息 所以 appName, (中文(简体) ), messageTemplate, (中文(简体) ), webOtpDomain,以及 otp.length 什么都不做——在供应商那里配置这些. expiry, (中文(简体) ), otp.maxAttempts,以及 otp.cookieName 仍然适用; expiry 限定本包的质疑记录,而供应商执行自己的代码寿命,以到期为准先结束尝试.
默认消息( 与 webOtpDomain set)看起来像:
Your MyApp sign-in code is: 123456
@myapp.example #123456
最后一句话是 源代码格式 (a WICG spec由Apple和Google共同编辑——什么) 网络OTP safari的代码自动填充分析。 人可读的句子也很重要:苹果公司没有发布iOS安全代码AutoFill的精确语法,该语法从消息文本中快速承认了代码(参见: autocomplete="one-time-code" 关于 MDN(b) —— Your <app> sign-in code is: <code> 遵循广泛观察的规律。 自定义模板应该保持类似形状,以便自动填充工作.
电话号码
输入规范化(空格、破折号、圆点、括号被剥去;正向) 00 → +),然后必须是有效的 页:1 (单位:千美元)+ 和需要的国家代码)——提供商从不猜测默认国家. normalizePhoneNumber 如果您想要相同的常态客户端,则导出.
测试模式: 抓取运输
在e2e测试中,包装你的 SmsTransport 内 CaptureSmsTransport 然后通过只测试的路由读取代码(在测试-模式env var上) 财务报告和审定财务报表 而不是需要电话——或支付文字费用.
import { CaptureSmsTransport } from "@activescott/auth-provider-sms/testing"
export const smsTransport =
process.env.E2E_TEST_MODE === "true"
? new CaptureSmsTransport(new TwilioTransport({ ... }))
: new TwilioTransport({ ... })
// in your gated readback route:
const captured = smsTransport.getCapturedSms(phone) // { message, code }
代码解析出默认信件模板; 通过第二个参数到 CaptureSmsTransport 当配置自定义时 messageTemplate它住在这里 /testing 子路径而不是软件包根,所以它不包含在应用程序的默认导入图中 .
安保模式
与电子邮件提供者相同的挑战模式:每发一次服务器侧式挑战,只存储为盐分的SHA-256散列,尝试数 在此之前 每次比较(封顶于 maxAttempts),常时比较,单用(在成功时被删除),挑战被HttpOnly cookie捆绑在启动浏览器上——没有它,单用代码是无用的.
与一个 VerificationTransport 代码从未到达您的服务器, 所以没有散列存储; 质疑记录持有电话号码和供应商的参考。 其他一切都没有改变,包括计算尝试 在此之前 向供应商提出问题,这也限制了一个挑战可以产生多少可开具账单的检查.
平均每艘和每艘IP派出减速舰 @activescott/auth 并默认执行(参见其 虐待保护 供应商一级的欺诈/泵卫兵(Twilio,AWS)仍然值得在顶端启用.
如果你认为这些应该不同——属于这个图书馆的保护,模型中的一个弱点——请 打开一个问题或 PR 讨论.