Server integration

サーバー連携

API パラメーターと公式 SDK の例を使い、サイトに端末登録と確認フローを組み込みます。

AuthLink の本番 API は https://api.getauthlink.com です。業務バックエンドには自サイトの API を指定し、AuthLink 公式サイトのドメインは API 呼び出しに使いません。

連携フローと信頼境界

公式 SDK でスマートフォンによる確認を組み込みます。連携用の認証情報はサイトのバックエンドでのみ保管し、以下の手順に沿ってリクエストを作成し、結果を処理してください。
  1. 運営者がサイト専用のテナントを作成し、認証情報をサイトのバックエンドへ渡します。
  2. バックエンドがログイン済みセッションから安定したユーザー ID を取得し、ランダムな state と作成用・消費用の冪等キーを生成します。
  3. bind / confirm リクエストを作成し、ユーザー、セッション、用途、state、requestId、expiresAt、冪等キーを保存します。その後、公開 ticket のみをブラウザーに返します。
  4. ユーザーが AuthLink でサイト、アカウント、数字を照合し、リクエストを承認します。
  5. approved / consumed を取得したら、保存済みの state と消費用キーで consume を呼び出します。
  6. 受領結果を検証し、自分のデータベースのトランザクションで requestId / verificationId を一意に保存してから confirmed を返します。保護対象の処理はこの記録を確認します。

webhook はありません。approved、6 桁の数字、フロントエンドのコールバックだけで処理を許可してはいけません。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 / 必須 表示可能な ASCII(0x21~0x7e)の 1~128 バイト。ログイン済みセッションから取得し、再利用やブラウザーによる指定を許可しません。
accountLabel string / 必須 空文字不可、UTF-8 で最大 160 バイト。制御文字と指定された双方向制御文字を拒否します。
purpose string / 必須 初回登録は bind、登録後の確認は confirm
state string / 必須 32 バイトの安全な乱数をパディングなし Base64URL にした 43 文字。バックエンドに保存し、消費時に元の値と照合します。

成功時は HTTP 200 と ticket を返します。

レスポンスのフィールド 意味
requestId 43 文字のリクエスト識別子
purpose / expiresAt リクエストの用途と UTC ISO 形式の有効期限。有効期間は 120 秒です
qr QR の JSON 文字列:v、origin、requestId、token。フロントエンドのコンポーネントまたはアプリのみに渡し、ログには残しません。
qrSvg 互換用のフィールドです。公式 Web パッケージは QR を自ら生成し、この値を innerHTML で挿入しません
pairingCode 現在の 6 桁の文字列。先頭のゼロを保持してください
displayCode value、serverTime、validUntil、periodSeconds:30

同じアカウントの新しいリクエストは、未完了の古いリクエストを拒否します。数字の更新で有効期限は延長されず、リクエストの再作成も不要です。

状態・消費・アカウント API

メソッド / パス 入力 戻り値 / 補足
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"} 承認後に消費して 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 ユーザーは削除しません。
消費結果のフィールド 検証内容
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 モジュールは未リリースです。サイトの 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 は null を許容する *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 の元の文字列を保持してください。戻り値の構造体には公式 Web コンポーネント向けの JSON タグがあります。未知のフィールド、重複キー、大文字小文字の別名は拒否します。仕様のフィールド変更時は 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) リクエストを作成します。フィールドは上表を参照してください。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 の相対パスを保持し、Web コンポーネントは 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":"..."}。未知のエラーを成功として扱わないでください。API レスポンスの共有キャッシュは禁止です。bearer キー、QR token、証明全体、秘密情報をログに残さないでください。