@ activescott/ auth- professor- 电子邮件
电子邮件魔法链接认证提供者 @activescott/auth。 。 。 .
发送包含一款单用魔法链接和一款数字一次性代码的签名电子邮件,两者均由一款服务器侧面挑战支持. 重新查找或创建用户 UserStore编号 :IdentityStore 并手控回认证核心 发行会话饼干.
用于生产 frumblefeed.com (英语) 财务报告和审定财务报表 (原始内容存档于2018-10-21). dinkerbellbot.com。 。 。 .
安装
npm install @activescott/auth @activescott/auth-provider-email
使用量
import { Auth } from "@activescott/auth"
import { EmailProvider } from "@activescott/auth-provider-email"
const auth = new Auth({
// ...session, identityStore, userStore, challengeStore...
providers: [
new EmailProvider({
smtp: {
host: process.env.SMTP_HOST!,
port: Number(process.env.SMTP_PORT),
user: process.env.SMTP_USER!,
pass: process.env.SMTP_PASS!,
},
from: process.env.FROM_EMAIL!,
template: { appName: "My App", subject: "Sign in to My App" },
}),
],
})
注册路线
提供者处理四个 URL 模式 /auth/email/* (由您的框架适配器挂起):
| 方法 | 路径 | 目的 |
|---|---|---|
| 邮政 | /auth/email/initiate | 发送到所提供邮件的神奇链接 . |
| 邮政 | /auth/email/send | 别名 initiate。 。 。 . |
| 获取 | /auth/email/verify | 从链接中校验令牌, 登录用户 . |
| 邮政 | /auth/email/verify | 验证一次性代码( 当 otp 已启用). |
| 获取 | /auth/email/callback | 别名 verify。 。 。 . |
登录邮件是如何工作的
每次发送都会创建一个服务器侧的挑战(通过 Auth 配置的 challengeStore(a) 有两条救赎路径,既单用,又共用一条过期(默认为15米):
- 神奇的链接 —— 说
/auth/email/verify?challenge=<id>&key=<256-bit secret>。单击(GET)显示最小值 "确认注册" 页面;确认按钮 POST 救赎。 电子邮件安全扫描仪(Outlook SafeLinks, Mimecast, 链接预览)预设了GET链接,但从未提交表格,因此无法消耗单用链接. - 数字代码 ——用户在您的登录页面上输入,而不是点击链接. iOS 和 macOS 在 Mail 中检测代码, 并在输入使用时通过 AutoFill 提供
autoComplete="one-time-code"。 。 。 .initiate仅设置 Httpauth_challengecookie 绑定启动浏览器的代码条目; 您的代码输入 POST 到/auth/email/verify。代码是尝试封装的:错误代码 =INVALID_CREDENTIALS,太多尝试 ~RATE_LIMITED页:1EXPIRED_TOKEN。 。 。 .
没有签名邮件的签名秘密管理——链接密钥和代码都被存储在挑战中被盐化的散列上,并在使用时被删除.
调音 : expiry (上层,例如:. "15m"和 otp: { length?, maxAttempts?, cookieName? },或 vars 环境 EMAIL_EXPIRY, (中文(简体) ), EMAIL_OTP_LENGTH, (中文(简体) ), EMAIL_OTP_MAX_ATTEMPTS 与 emailConfigFromEnvironment。 。 。 .
initiate 拒绝一个其域名没有点的地址(例如:. scott@willeke在任何商店写作或发送之前,因为它几乎总是缺少TLD而不是真正的目的地. 设定 allowDotlessDomain: true 用于内部网络或编程设置,以登录到一个赤裸的主机名,例如 user@localhost。 。 。 .
Dev 模式( 不需要 SMTP)
NodemailerTransport 接受一个 isDevelopment 旗帜。 何时 true,它通过Nodemailer的流传输来缓冲电子邮件(没有真正的SMTP连接)并打印到服务器控制台的魔法链接——对本地的dev,example,以及CI有用:
import {
EmailProvider,
NodemailerTransport,
} from "@activescott/auth-provider-email"
new EmailProvider(
{/* ...config... */},
new NodemailerTransport(true), // dev mode: log link, don't send
)
或没有通过任何运输 和提供者自动创建 new NodemailerTransport(process.env.NODE_ENV === "development")。 。 。 .
自定义电子邮件传输
船舶 NodemailerTransport (SMTP) (中文(简体) ). 执行 EmailTransport 用于插入Resend、SES、Postmark等:
import type {
EmailProviderConfig,
EmailTransport,
} from "@activescott/auth-provider-email"
class ResendTransport implements EmailTransport {
async sendMagicLink(
to: string,
magicLink: string,
config: EmailProviderConfig,
): Promise<boolean> {
// ...call Resend API...
return true
}
}
new EmailProvider(config, new ResendTransport())
测试模式: 抓取运输
在e2e测试中,包装你的 EmailTransport 内 CaptureEmailTransport,通过一个仅测试的回读路径(在测试-模版env var上显示)来显示它记录的内容 财务报告和审定财务报表 a supre-secret header),并驱动真实的确认页或代码输入流——没有SMTP服务器,没有收件箱投票.
import { CaptureEmailTransport } from "@activescott/auth-provider-email/testing"
// Install it only under your test-mode flag: what it holds are live sign-in
// credentials for as long as the challenge lives.
export const emailTransport =
process.env.E2E_TEST_MODE === "true"
? new CaptureEmailTransport(new NodemailerTransport())
: new NodemailerTransport()
// in your gated readback route:
const captured = emailTransport.getCapturedEmail(email) // { magicLink, code }
它住在这里 /testing 子路径而不是软件包根,所以它不包含在应用程序的默认导入图中 。 见下文可操作的例子.
文档实例( E)
Full Docs 和一个带有 Playwright 测试的可运行的 React Router 框架- mode 实例在 monrepo 中直播 :
→ https://github.com/活塞斯科特/奥斯** 联合国
许可证
麻省理工学院