mcpField
S
sumsub-api-auth

sumsub-api-auth

github.com/sumsub開発71.2k 回インストール4 週間前に更新
リポジトリ

sumsub-api-auth について

Sumsub API の App Token 認証を行う Claude スキルです。HMAC-SHA256 署名とサンドボックス資格情報の扱いを説明し、署名用スクリプトも備えています。

主な機能

  1. 01HMAC-SHA256 リクエスト署名
  2. 02サンドボックス資格情報の保護
  3. 03ヘッダー生成スクリプト
  4. 04署名付き curl リクエスト
  5. 05マルチパート署名の手順

活用シーン

  1. 01401 署名エラーの調査
  2. 02単発の署名付き API 呼び出し
  3. 03申請者の本人確認書類のアップロード

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sumsub/agent-skills --skill sumsub-api-auth

インストール後、Claude Code で/sumsub-api-authを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
signing-pitfalls.md
scripts/
sumsub_curl.sh
sumsub_sign.py

詳細

Sumsub — API 認証(App Token)

公式リファレンスに基づき、https://api.sumsub.com に対して認証済みリクエストに署名して送信する方法です。

⚠️ サンドボックストークンのみ

本番環境の Sumsub App Token/シークレットを Claude と共有、貼り付け、または使用しないでください。 ユーザーが本番トークンを提示した場合は断り、代わりに https://cockpit.sumsub.com/checkus/home?sbx=true で生成したサンドボックスのペアを求めてください(AI エージェントに Sumsub を接続 -> ビルドと設定 -> トークンを生成)。

  • サンドボックストークンは、ダッシュボードがサンドボックスモードのときに作成されます。サンドボックスデータのみにアクセスできるため、漏えいしても実際の申請者の個人情報をさらしたり、実際のお金を移動したりすることはできません。
  • 本番トークンは、本人確認書類を含む、本番申請者への完全なプログラムアクセス権を付与します。銀行の認証情報と同様に扱ってください。
  • Sumsub は、トークンの作成時の環境にトークンを固定します。サンドボックストークンは本番データに対して 401 を返し、その逆も同様です。そのため、サンドボックスを必須にすることは、実用上のデフォルトでもあります。

ユーザーが本番環境のシークレットと思われるものを会話に貼り付けた場合は、すぐに注意を促し、ダッシュボードでのローテーションを勧めてください。そのうえで、新たに生成したサンドボックスのペアを使用する場合にのみ続行してください。

ユーザーから取得する情報

変数入手先
SUMSUB_APP_TOKENhttps://cockpit.sumsub.com/checkus/home?sbx=true — AI エージェントに Sumsub を接続 -> ビルドと設定 -> トークンを生成。一度だけ表示されます。
SUMSUB_SECRET_KEYトークンと同じダイアログに表示されます。これも一度だけ表示されます。
SUMSUB_BASEhttps://api.sumsub.com(サンドボックスと本番環境で同じホストです。モードはトークンによって決まります)。

⚠️ トークンとシークレットは作成時に一度だけ表示されます。 ダイアログを閉じる前に、両方を .env(またはシークレットストア)にコピーしてください。復元する方法はなく、再生成のみ可能です。

ユーザーには、.claude/settings.local.json(gitignore 対象で、Claude Code が自動読み込みします)または .env に保存するよう案内してください。

// .claude/settings.local.json
{
  "env": {
    "SUMSUB_APP_TOKEN": "sbx:...",
    "SUMSUB_SECRET_KEY": "..."
  }
}
# .env
SUMSUB_APP_TOKEN=sbx:...
SUMSUB_SECRET_KEY=...

いずれかの認証情報がない場合は、処理を中止してユーザーに確認してください。プレースホルダーを作らないでください。

必須の 3 つのヘッダー

api.sumsub.com へのすべてのリクエストには、次の情報が必要です。

ヘッダー値
X-App-TokenApp Token をそのまま指定します。
X-App-Access-Ts現在の Unix 時刻を秒単位(UTC)で指定します。Sumsub の時刻との差は ±60 秒以内でなければなりません。
X-App-Access-Sig署名文字列をシークレットキーとして計算した HMAC-SHA256 の小文字の 16 進数値です。

HTTPS は必須です。通常の http:// は拒否されます。

署名文字列

区切り文字を使わずに連結します。

<ts><HTTP_METHOD_UPPER><request_uri_with_query><body_bytes_or_empty>
  • ts — X-App-Access-Ts に指定する正確な値(数字の文字列)です。
  • HTTP_METHOD_UPPER — GET、POST、PATCH、PUT、DELETE を大文字で指定します。
  • request_uri_with_query — / で始まるパスです。クエリ文字列がある場合は含めます。例:/resources/applicants/-/one、 /resources/accessTokens?userId=abc&levelName=basic-kyc-level。
  • ボディ — 送信する生のバイト列です。ボディのない GET/DELETE では、何も追加しません(空文字列)。JSON の場合は、送信するものとまったく同じバイト列に署名してください。後から再シリアライズすると、署名が無効になります。

次に hex(hmac_sha256(secret, signing_string)) を計算し、小文字で指定します。

実例(ドキュメントより)

時刻が 1607551635 で、ボディなしの POST /resources/accessTokens?userId=...&levelName=basic-kyc-level&ttlInSecs=600 を送信する場合の署名文字列:

1607551635POST/resources/accessTokens?userId=cfd20712-24a2-4c7d-9ab0-146f3c142335&levelName=basic-kyc-level&ttlInSecs=600

リファレンス実装

各言語の公式サンプルは sumsub/AppTokenUsageExamples (Java、JS、Python、Ruby、Go、PHP、C#)にあります。本番環境への統合にはこちらを使用してください。

単発の呼び出しやデバッグ用に、このスキルには2つの小さなヘルパーが含まれています。

  • scripts/sumsub_sign.py — 指定したメソッド、パス、本文に対する3つのヘッダーを出力します。ネットワーク呼び出しは行いません。
  • scripts/sumsub_curl.sh — 署名と curl を一度に実行します。環境変数から SUMSUB_APP_TOKEN / SUMSUB_SECRET_KEY を読み込みます。

作業ディレクトリにかかわらず正しくスクリプトを実行できるよう、${CLAUDE_SKILL_DIR}/scripts/<script> を使ってください。

簡単な確認 — 現在の申請者数を取得する
export SUMSUB_APP_TOKEN='sbx:...'   # sandbox token, refuse prod
export SUMSUB_SECRET_KEY='...'

${CLAUDE_SKILL_DIR}/scripts/sumsub_curl.sh GET '/resources/applicants/-/count'

JSON 本文を含む 200 が返れば、署名が正しいことを確認できます。{"description":"Invalid signature"} を含む 401 が返った場合、署名文字列またはシークレットに誤りがあります。次の順に再確認してください。

  1. トークンとシークレットの組み合わせが一致している(コピー&ペースト時に切り詰められることがよくあります)。
  2. タイムスタンプがミリ秒ではなく秒で、システム時計が同期している。
  3. パスに先頭の / とクエリ文字列全体が含まれている。
  4. 署名した本文のバイト列と送信するバイト列が完全に一致している(エディターやヒアドキュメントによって末尾に改行が追加されていないか確認してください)。
  5. メソッドが大文字になっている。

multipart/form-data リクエストへの署名

一部のエンドポイントでは、ファイルのアップロードが必要です。最も一般的なのは、idDoc の写真をアップロードする POST /resources/applicants/{applicantId}/info/idDoc です。この場合:

  • 境界マーカー、各パートのヘッダー、JSON メタデータ、ファイルのバイト列を含め、未加工の multipart 本文全体にバイト単位で署名してください。multipart 固有の例外はありません。JSON と同じルールが適用されます。 署名文字列 = ts + METHOD + path + body_bytes
  • Content-Type ヘッダーは multipart/form-data; boundary=<boundary> です。<boundary> は、署名した本文のバイト列に含まれるものと一致している必要があります。

注意点は、ほとんどの HTTP ライブラリ(curl -F、files= を使った requests、FormData を使った fetch)が境界を内部で生成し、正確なバイト列を公開しないことです。そのため、送信される内容に署名することはできません。回避策として、本文を自分でメモリー上に構築してハッシュ化し、その正確なバイト列を --data-binary または生の送信機能で送信してください。

Python の例(標準的な方法)
import hashlib, hmac, json, os, time, uuid
from pathlib import Path
from urllib.request import Request, urlopen

APP_TOKEN = os.environ["SUMSUB_APP_TOKEN"]
SECRET    = os.environ["SUMSUB_SECRET_KEY"]
APPLICANT = "6a170f852f9d88fe6eda2636"          # from create-applicant response
FILE      = Path("/path/to/passport.png")
METADATA  = {"idDocType": "PASSPORT", "country": "RUS"}

boundary = "----sumsub-" + uuid.uuid4().hex
crlf = b"\r\n"
parts = [
    b"--" + boundary.encode(),
    b'Content-Disposition: form-data; name="metadata"',
    b"Content-Type: application/json",
    b"",
    json.dumps(METADATA).encode(),
    b"--" + boundary.encode(),
    f'Content-Disposition: form-data; name="content"; filename="{FILE.name}"'.encode(),
    b"Content-Type: image/png",
    b"",
    FILE.read_bytes(),
    b"--" + boundary.encode() + b"--",
    b"",
]
body = crlf.join(parts)

method, url_path = "POST", f"/resources/applicants/{APPLICANT}/info/idDoc"
ts = str(int(time.time()))
sig = hmac.new(
    SECRET.encode(),
    ts.encode() + method.encode() + url_path.encode() + body,
    hashlib.sha256,
).hexdigest()

req = Request(
    "https://api.sumsub.com" + url_path,
    data=body, method="POST",
    headers={
        "X-App-Token": APP_TOKEN,
        "X-App-Access-Ts": ts,
        "X-App-Access-Sig": sig,
        "Content-Type": f"multipart/form-data; boundary={boundary}",
        "Content-Length": str(len(body)),
        "X-Agent-Source": "sumsub-skills",
        "X-Agent-Source-Ver": "1.5.0",
    },
)
print(urlopen(req).read().decode())

Curl を使った代替方法(例:本文をディスク上に作成した後、curl --data-binary @raw-multipart.bin を実行する方法)も使えます。ただし、本文内の境界と Content-Type 内の境界を完全に一致させる必要があります。コード内で両者を同期させるほうが簡単です。

SDK アクセストークンの生成(よくある次の手順)

認証が機能した後に最もよく使われるエンドポイントは次のとおりです。

POST /resources/accessTokens?userId=<your_user_id>&levelName=<level>&ttlInSecs=600

本文は空です。レスポンスに含まれる token を Web / Mobile SDK に渡してください。 完全なリファレンスはこちらです:https://docs.sumsub.com/reference/generate-access-token。

関連項目

コメント