Server integration

伺服器端接入

為你的網站整合手機綁定與確認流程,提供 API 參數說明和官方 SDK 範例。

AuthLink 正式 API 為 https://api.getauthlink.com;網站業務後端地址仍填寫你自己的 API,官網網域不用於介面呼叫。

接入流程與信任邊界

透過官方 SDK 整合手機確認流程。接入憑證僅儲存在網站後端,請依下方說明建立請求並處理確認結果。
  1. 運營方為網站創建獨立租戶,把憑據交付網站後端。
  2. 後端從已登錄 session 取得穩定使用者 ID,生成隨機 state、創建冪等鍵和獨立消費冪等鍵。
  3. 創建 bind / confirm 請求,保存使用者、會話、用途、state、requestId、expiresAt 及冪等鍵,再把公開 ticket 返回瀏覽器。
  4. 使用者在 AuthLink App 中核對網站、帳號和數字,然後批准請求。
  5. 後端查詢到 approved / consumed 後,使用保存的 state 和消費冪等鍵調用 consume。
  6. 校驗回執,在自己的資料庫事務中以 requestId / verificationId 唯一約束記錄確認,才向網頁返回 confirmed。受保護業務檢查該記錄。

沒有 webhook。approved、六位數字以及前端回呼都不能直接放行業務。AuthLink 不接收 action、金額、transactionHash 或業務授權範圍。

租戶與鑒權

向營運方取得本站的 tenantId、apiKey、origin 和 expiresAt。新金鑰永久有效;營運方仍可輪換、撤銷金鑰或停用租戶。舊金鑰保留原有效期限,僅在網站後端安全保存。

請求頭 要求
Authorization Bearer <tenant API key>,全部 integration 接口必填
Content-Type POST 使用 application/json;拒絕未知字段和重復 JSON 鍵
Idempotency-Key 創建和消費必填,16–128 位字母、數字、下划線或連字符。建議 32 位元組安全隨機 Base64URL;同次網路重試復用
Origin / Cookie API 不接受瀏覽器 Origin 或 Cookie;網頁通過自己的網站後端接入

創建請求與參數

POST /v1/integration/requests · API origin:


{
  "externalUserId": "stable-user-id",
  "accountLabel": "Account display name",
  "purpose": "bind",
  "state": "REPLACE_WITH_SAVED_43_CHARACTER_RANDOM_STATE"
}
字段 類型 / 必填 說明
externalUserId string / 是 1–128 位元組可打印 ASCII(0x21–0x7e)。由登錄 session 取得,不可回收或由瀏覽器決定
accountLabel string / 是 非空,最多 160 個 UTF-8 位元組;拒絕控制字符及指定雙向控制字符
purpose string / 是 首次綁定 bind,已綁定後確認 confirm
state string / 是 32 位元組安全隨機數,無 padding Base64URL,43 字符;後端保存並在消費時原樣核對

成功返回 HTTP 200 和 ticket:

返回字段 含義
requestId 43 字符請求標識
purpose / expiresAt 請求用途和 UTC ISO 時間;有效期 120 秒
qr QR JSON 字符串:v、origin、requestId、token;只交給前端元件或 App,禁止寫入日誌
qrSvg 伺服器端兼容字段;官方網頁包會自行生成 QR,不使用 innerHTML 插入此字段
pairingCode 當前六位字符串,保留前導零
displayCode value、serverTime、validUntil、periodSeconds:30

同一帳號的新請求會拒絕舊的未完成請求。數字更新不延長期限,不需要另建請求。

狀態、消費與帳號接口

方法 / 路徑 輸入 返回 / 說明
GET /v1/integration/requests/{id} 租戶 bearer requestId、status、expiresAt、displayCode(可選)。new / pending / approved / consumed / rejected / expired
POST /v1/integration/requests/{id}/consume 租戶 bearer、Idempotency-Key,body {"state":"saved-43-character-state"} approved 後領取 confirmed 回執;網路結果不明時復用原消費鍵
POST /v1/integration/accounts/status 租戶 bearer,body {"externalUserId":"..."} externalUserId、status:unbound/bound/deleted、platform(未綁定為 null)
POST /v1/integration/accounts/delete 租戶 bearer,body {"externalUserId":"..."} {"status":"deleted"};永久撤銷本站 AuthLink 綁定,不能重綁;不刪除 CMS 帳號
consume 返回字段 核驗要求
status / authenticationPolicy status 必須為 confirmed;authenticationPolicy 由官方 SDK 驗證
requestId / tenantId / externalUserId 必須對應當前請求、租戶、已登錄使用者和已保存會話
purpose / state / expiresAt 與後端持久保存值完全一致,期限未過
verificationId / platform / consumedAt 校驗結果 ID、android / ios 與有效時間;以唯一約束落庫
刪除表示永久撤銷 AuthLink 綁定。不要據此自動刪除 CMS 使用者;需要確認的業務也不能在撤銷後跳過驗證。

Go SDK 與方法

獨立模塊 authlink.local/sdk,Go 1.22+,只依賴標準庫。適合 Go 網站後端;不需要引入整個 AuthLink 伺服器端或 MySQL 驅動。

本頁已包含安裝步驟、參數說明、錯誤處理和完整範例,可直接閱讀並複製程式碼。

下載 Go SDK 原始碼包 · 線上查看完整範例 →

安裝與初始化

解壓縮後保留 SDK 自己的 go.mod;僅將 SDK 模組接入你的網站專案。

SDK 當前隨原始碼交付,未發佈公共 Go module。在你的網站 Go 項目中解壓,使用本地 replace:


mkdir -p third_party
tar -xzf authlink-go.tar.gz -C third_party
go mod edit -replace=authlink.local/sdk=./third_party/authlink-go
go mod edit -require=authlink.local/[email protected]
go mod tidy

import authlink "authlink.local/sdk"

client, err := authlink.New(authlink.Config{
    Origin:   "https://api.getauthlink.com", // API origin, not the marketing site
    TenantID: os.Getenv("AUTHLINK_TENANT_ID"),
    APIKey:   os.Getenv("AUTHLINK_API_KEY"),
})
if err != nil { return err }

// Get userID and label from your authenticated website session.
state, err := authlink.RandomToken()
if err != nil { return err }
createKey, err := authlink.RandomToken()
if err != nil { return err }
consumeKey, err := authlink.RandomToken()
if err != nil { return err }
// Persist state, both keys and user/session first. Reuse them on retries.
ticket, err := client.CreateRequest(ctx, authlink.CreateInput{
    ExternalUserID: userID, AccountLabel: label,
    Purpose: "bind", State: state,
}, createKey)
if err != nil { return err }
expected := authlink.Expected{
    RequestID: ticket.RequestID, ExternalUserID: userID,
    Purpose: ticket.Purpose, State: state, ExpiresAt: ticket.ExpiresAt,
}
// Save expected and consumeKey before returning the public ticket.

// Load saved expected / consumeKey after checking session, CSRF and ownership.
status, err := client.Status(ctx, expected.RequestID)
if err != nil { return err }
if status.Status == "approved" || status.Status == "consumed" {
    result, err := client.Consume(ctx, expected, consumeKey)
    if err != nil { return err }
    // The SDK has validated the full receipt. Persist a unique confirmation
    // in your own transaction, associated with this user/session and business.
    _ = result
}
Config 參數說明
Origin / TenantID / APIKey必填,API HTTPS origin(無末尾斜槓)、租戶 ID、私有後端金鑰
AllowLocalHTTP預設 false;只允許回環 / localhost 開發測試
HTTPClient可選 *http.Client;SDK 複製後禁止重定向、禁用 CookieJar。transport 需可信,每次請求有 10 秒上限,父 context 和更短的 client timeout 優先
方法返回與用途
CreateRequest(ctx, CreateInput, key)(Ticket, error),CreateInput:ExternalUserID、AccountLabel、Purpose、State;預設用途 confirm,首次綁定 bind
Status(ctx, requestID)(RequestStatus, error),查詢狀態與當前 displayCode,不能直接當作業務確認
Consume(ctx, Expected, key)(Confirmation, error),消費並校驗策略、租戶、使用者、請求、用途、state、期限、結果 ID 和平台
WaitForConfirmation(ctx, Expected, key, interval)(Confirmation, error),可選後端輪詢;approved / consumed 後消費。interval=0 預設 1500 毫秒,允許 100 毫秒–10 秒
AccountStatus(ctx, externalUserID)(AccountStatus, error),查詢 unbound / bound / deleted;Platform 為可空 *string
DeleteAccount(ctx, externalUserID)error;永久撤銷本站 AuthLink 綁定,原帳號不可重綁,不刪除 CMS 使用者
RandomToken()(string, error),32 位元組安全隨機 Base64URL;state、創建鍵和消費鍵分別生成並保存
ValidateConfirmation(result, expected, tenantID, now)error,純字段校驗;不是簽章驗證器,不能把瀏覽器自報回執當可信授權

Expected 包含 RequestID、ExternalUserID、Purpose、State、ExpiresAt;從後端已保存的請求讀取,保持原 expiresAt 字符串。返回類型均帶協議 JSON tag,可編碼給官方網頁元件。SDK 拒絕未知字段、重復鍵和大小寫別名;協議增加字段時需要同步升級 SDK。

等待、取消與錯誤處理


result, err := client.WaitForConfirmation(ctx, expected, consumeKey, 0)
switch {
case err == nil:
    // Persist result in your own transaction before updating UI or authorizing work.
    _ = result
case errors.Is(err, authlink.ErrRejected):
    // The user rejected the request.
case errors.Is(err, authlink.ErrExpired):
    // The request expired.
case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):
    // This call was canceled or timed out; the platform request is not revoked.
default:
    var api *authlink.APIError
    if errors.As(err, &api) {
        // Handle api.StatusCode / api.Code; retry with the same consumption key.
    }
}
沒有自動網路重試。網路結果不明時復用已保存的冪等鍵;僅已消費、校驗且在網站資料庫落庫的結果可以用於業務。網頁輪詢接口通常使用 Status + Consume,WaitForConfirmation 適合後端長等待。

Go 完整範例

範例使用兩個階段:create 建立請求,result 查詢並消費已儲存的請求。只在使用者完成手機確認後執行 result。範例不包含網站的工作階段管理和資料庫持久化,不能直接取代業務授權。

展開或收合完整 Go 範例
// This example creates a request, then queries/consumes a previously saved one.
// Supply tenant credentials only through your backend's private environment.
package main

import (
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"time"

	authlink "authlink.local/sdk"
)

func run() error {
	mode := flag.String("mode", "create", "create or result")
	user := flag.String("user", "", "stable user ID from your authenticated session")
	label := flag.String("label", "", "account display label")
	purpose := flag.String("purpose", "bind", "bind or confirm")
	flag.Parse()
	client, err := authlink.New(authlink.Config{Origin: os.Getenv("AUTHLINK_ORIGIN"), TenantID: os.Getenv("AUTHLINK_TENANT_ID"), APIKey: os.Getenv("AUTHLINK_API_KEY")})
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	switch *mode {
	case "create":
		// For this standalone example, supply already-generated and saved values
		// through the environment. A website must persist them before networking.
		ticket, err := client.CreateRequest(ctx, authlink.CreateInput{ExternalUserID: *user, AccountLabel: *label, Purpose: *purpose, State: os.Getenv("AUTHLINK_STATE")}, os.Getenv("AUTHLINK_CREATE_KEY"))
		if err != nil {
			return err
		}
		// Contains QR token: deliver to the intended user's UI; never log it.
		return json.NewEncoder(os.Stdout).Encode(ticket)
	case "result":
		expected := authlink.Expected{RequestID: os.Getenv("AUTHLINK_REQUEST_ID"), ExternalUserID: *user, Purpose: *purpose, State: os.Getenv("AUTHLINK_STATE"), ExpiresAt: os.Getenv("AUTHLINK_EXPIRES_AT")}
		status, err := client.Status(ctx, expected.RequestID)
		if err != nil {
			return err
		}
		if status.Status != "approved" && status.Status != "consumed" {
			return json.NewEncoder(os.Stdout).Encode(status)
		}
		result, err := client.Consume(ctx, expected, os.Getenv("AUTHLINK_CONSUME_KEY"))
		if err != nil {
			return err
		}
		// In a website, persist result atomically with unique request/result IDs,
		// user/session and business association before returning confirmed.
		_ = result
		fmt.Fprintln(os.Stderr, "Receipt validated; this example does not persist or authorize business.")
		return nil
	default:
		return errors.New("mode must be create or result")
	}
}

func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

執行參數

參數用途
-modecreate 建立請求;result 查詢和消費結果,預設 create。
-user已登入網站使用者的穩定 ID,由後端工作階段取得。
-label建立請求時顯示的帳號名稱。
-purpose首次綁定使用 bind;後續確認使用 confirm,範例預設 bind。

後端環境變數

變數用途
AUTHLINK_ORIGIN / AUTHLINK_TENANT_ID / AUTHLINK_API_KEY由營運方提供的 API 位址、租戶 ID 和後端金鑰,僅儲存在網站後端。
AUTHLINK_STATE / AUTHLINK_CREATE_KEY / AUTHLINK_CONSUME_KEY後端分別產生並持久儲存的 state、建立冪等鍵和消費冪等鍵;重試時重用。
AUTHLINK_REQUEST_ID / AUTHLINK_EXPIRES_ATresult 階段從後端儲存的 ticket 讀取請求 ID 和原始到期時間。

完整範例已包含在 SDK 整包的 examples/quickstart/main.go 中。可複製上方程式碼儲存為 main.go;憑證透過後端環境注入,不要寫入程式碼或瀏覽器。

# Run from a Go project that already includes the SDK module.
# Supply the private environment variables listed above before running.
export AUTHLINK_ORIGIN=https://api.getauthlink.com
go run . -mode create -user stable-user-id -label "Example account" -purpose bind

# After phone approval, load the SAME saved request context before running:
go run . -mode result -user stable-user-id -purpose bind

Node SDK 與方法


// Copy /sdk/node/ and /sdk/browser/ with their relative paths. Server import only.
import { AuthLink, randomToken } from './sdk/node/authlink.mjs';
const auth = new AuthLink({
  origin: 'https://api.getauthlink.com',
  tenantId: process.env.AUTHLINK_TENANT_ID,
  apiKey: process.env.AUTHLINK_API_KEY,
});
// user must come from your authenticated session. This is the creation stage.
const state = randomToken();
const createKey = randomToken();
const consumeKey = randomToken();
// Persist these values and user/session before networking. Reuse on retries.
const ticket = await auth.createRequest({
  externalUserId: user.id, accountLabel: user.displayName,
  purpose: 'bind', state,
}, createKey);
const expected = { requestId: ticket.requestId, expiresAt: ticket.expiresAt,
  externalUserId: user.id, purpose: 'bind', state };
// Save expected, consumeKey and session association before returning ticket.

// Your result endpoint loads the saved request context:
const status = await auth.status(expected.requestId);
if (['approved', 'consumed'].includes(status.status)) {
  const verified = await auth.consume(expected, consumeKey);
  // The SDK has verified the receipt. Persist a unique confirmation atomically.
  // Return verified to the browser only after the database commit succeeds.
}
構造參數 / 方法 說明
origin / tenantId / apiKey 必填;API HTTPS origin(無末尾斜槓)、租戶 ID 和私有金鑰
allowLocalHttp 預設 false;僅本機回環開發
createRequest(input, key) 創建;input 字段見上表,purpose 未傳時預設 confirm
status(requestId, signal?) 查詢狀態;signal 為可選 AbortSignal
consume(expected, key, signal?) 消費並校驗回執,返回已驗證的結果
waitForConfirmation(expected, options) 後端輪詢工具;options.idempotencyKey 與 onConfirmed 必填;可選 onRejected / onExpired、signal、intervalMs(預設 1500,範圍 100–10000 毫秒);仍由業務持久化結果
accountStatus(id) / deleteAccount(id) 查詢 / 永久撤銷本站帳號綁定

安裝說明、方法參數和使用範例均在本頁。Node SDK 與所需依賴已合併為一個壓縮包,解壓縮後保留 node 與 browser 的相對目錄;網頁元件透過 npm 安裝。

下載 Node SDK 整包

mkdir -p sdk
tar -xzf authlink-node.tar.gz -C sdk
# Import ./sdk/node/authlink.mjs from your backend project.

錯誤處理

HTTP 常見 code 處理
400 INVALID_REQUEST / INVALID_SUBJECT / INVALID_DISPLAY_TEXT / INVALID_IDEMPOTENCY_KEY 按字段約束修正輸入;不要自動生成新請求掩蓋未知結果
401 UNAUTHORIZED / STATE_MISMATCH / SERVER_CREDENTIAL_REQUIRED 檢查私有憑據、state、Host 和是否繞過網站後端
404 NOT_FOUND 請求或發佈渠道不存在
409 APPROVAL_REQUIRED / REQUEST_EXPIRED / REQUEST_USED / IDEMPOTENCY_CONFLICT / ACCOUNT_ALREADY_BOUND / ACCOUNT_NOT_BOUND 按業務狀態處理,過期後由使用者重新發起,保留冪等恢復語義
429 RATE_LIMITED / BUSY 退避重試,復用原冪等鍵
503 ATTESTATION_UNAVAILABLE 驗證服務暫時無法使用,請稍後重試

錯誤 body 為 {"code":"..."}。未知錯誤不當成成功。接口響應不能共享緩存,禁止記錄 bearer、二維碼 token、完整證明和原始秘密。