One-click authorization

让用户使用 SafeW,一键登录网站

Login Widget 在你的网站中显示 SafeW 登录按钮。用户授权后,你会收到带签名的基础身份数据,再由服务端验证并建立自己的登录会话。

2 种 Callback 与 Redirect 模式
7 项 核心身份与授权字段
≤ 1h 建议授权数据有效时间
HMAC 服务端 SHA256 签名验证
01 / User journey

用户只看到一次清晰授权

复杂的签名验证留在服务端,前端只负责展示按钮、接收结果,并把数据安全地交给自己的后端。

减少注册步骤,不降低安全边界

用户确认授权后,网站获得必要身份字段。你的服务端验证 hash 和授权时间,再创建本地账号或登录会话。

01 / CLICK

用户点击按钮

进入 SafeW 授权确认

02 / AUTHORIZE

SafeW 返回数据

身份字段 + auth_date + hash

03 / VERIFY

服务端建立会话

验签通过后才允许登录

02 / Preparation

嵌入前先完成两件事

Login Widget 依赖 Bot 身份。域名绑定确保授权结果只返回给你控制的网站。

创建 Bot 并保存 Token

在 SafeW 中通过 BotFather 创建 Bot。Token 只保存于服务端,用于之后验证授权数据。

使用 /setdomain 绑定网站域名

绑定实际部署 Widget 的域名。建议让 Bot 头像与网站 Logo 保持一致,帮助用户识别授权对象。

03 / Choose a mode

Callback 还是 Redirect?

两者都能完成授权,区别在于授权结果如何回到你的应用。data-onauth 与 data-auth-url 必须二选一。

适合传统网站

Redirect 模式

授权后跳转到指定 URL,用户字段通过查询参数传递。

  • 后端路由可直接接收结果
  • 适合多页网站与服务端渲染
  • 回调地址必须使用 HTTPS
!
不要同时配置两种模式

data-onauth 和 data-auth-url 二选一;若两者都不设置,按钮会显示,但授权结果不会被你的应用处理。

04 / Embed

用一段脚本嵌入按钮

将 YOUR_BOT_USERNAME 替换为 Bot 用户名,不包含 @。Callback 模式中,回调函数收到 user 对象。

HTML + JavaScript · Callback
<script async
  src="https://oauth.safew.bot/js/safew-widget.js"
  data-safew-login="YOUR_BOT_USERNAME"
  data-size="large"
  data-onauth="onSafeWAuth(user)"
  data-request-access="write">
</script>

<script>
  function onSafeWAuth(user) {
    fetch("/auth/safew", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(user)
    });
  }
</script>
HTML · Redirect
<script async
  src="https://oauth.safew.bot/js/safew-widget.js"
  data-safew-login="YOUR_BOT_USERNAME"
  data-size="large"
  data-auth-url="https://your-site.com/auth/safew"
  data-request-access="write">
</script>
SIZE

按钮尺寸

large、medium、small,默认使用 large。

PIC

用户头像

data-userpic 控制是否显示,默认开启。

WRITE

消息权限

data-request-access="write" 可请求向用户发送消息的权限。

05 / Returned data

你会收到哪些字段?

字段用于识别用户和验证授权。last_name、username 与 photo_url 可能不存在,业务逻辑应允许这些字段为空。

字段 类型 用途
id Integer SafeW 用户唯一 ID
first_name String 用户名字
last_name String · 可选 用户姓氏
username String · 可选 SafeW 用户名
photo_url String · 可选 头像地址
auth_date Integer 授权 Unix 时间戳
hash String 服务端校验哈希
06 / Server verification

只有验签通过,才创建登录会话

客户端可以被篡改。必须把授权数据发送到服务端,以 Bot Token 派生密钥并验证 hash。

STEP 01 取出 hash 字段
STEP 02 剩余字段排序
STEP 03 换行连接 key=value
STEP 04 SHA256 派生密钥
STEP 05 HMAC 常量时间比对
Node.js · verify authorization
const crypto = require("crypto");

function verifySafeWLogin(payload, botToken) {
  const data = { ...payload };
  const receivedHash = data.hash;
  delete data.hash;

  if (!/^[a-f0-9]{64}$/i.test(receivedHash || "")) {
    return false;
  }

  const checkString = Object.keys(data)
    .sort()
    .map((key) => `${key}=${data[key]}`)
    .join("\n");

  const secretKey = crypto
    .createHash("sha256")
    .update(botToken)
    .digest();

  const computedHash = crypto
    .createHmac("sha256", secretKey)
    .update(checkString)
    .digest("hex");

  const hashIsValid = crypto.timingSafeEqual(
    Buffer.from(computedHash, "hex"),
    Buffer.from(receivedHash, "hex")
  );

  const age = Math.floor(Date.now() / 1000) - Number(data.auth_date);
  return hashIsValid && age >= 0 && age <= 3600;
}
登录安全底线

始终在服务端验证 hash;拒绝过期 auth_date;使用 timingSafeEqual;Bot Token 永不进入前端;登录回调全程使用 HTTPS。

不要与 Mini App 验签公式混用

Login Widget 使用 SHA256(bot_token) 作为 HMAC 密钥;Mini App 使用 HMAC-SHA256("WebAppData", bot_token) 派生密钥。