認証とロール

概要

Private Channelsには、JWT認証とロールベースのアクセス制御(RBAC)によってゲートウェイアクセスを管理するオプションのAuth Serviceが含まれています。認証が無効の場合、ゲートウェイはすべての接続を受け入れます。有効な場合、クライアントはすべてのリクエストに有効なJWTを提示する必要があります。

このページでは、以下の両方の対象者を扱います:

  • 開発者 - 登録、ログイン、ウォレット検証、および認証済みリクエストの実行
  • オペレーター - Authサービスの有効化、JWT_SECRETの設定、およびoperatorロールのプロビジョニング

認証の有効化

認証は、ゲートウェイとAuth Serviceの両方にJWT_SECRET(空でない値)を設定することで有効になります。Auth ServiceにはさらにAUTH_DATABASE_URLも必要です。

JWT_SECRETが設定されていない場合、ゲートウェイはオープンモードで動作し、トークンは不要です。

Docker Compose: Authサービスは Docker Compose プロファイルであり、デフォルトでは起動しません。含めるには、docker compose コマンドに --profile auth を渡してください。また、JWT_SECRET や POSTGRES_PASSWORD などのシークレットが正しく解決されるよう --env-file .env も合わせて指定してください(--env-file フラグが一つでも渡されると、Compose は自動的な .env の読み込みを無効化します):

docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet --env-file .env --profile auth up -d

Auth Service API

すべてのエンドポイントは /auth 以下にあります。Authサービスは AUTH_PORT(デフォルト 8903)でリッスンします。

POST /auth/register

新しいアカウントを作成します。すべてのユーザーは user ロールで登録されます。

{ "username": "alice", "password": "hunter2" }
  • ユーザー名:5〜32文字、英数字および _ と -
  • パスワード:6〜128文字
  • 作成されたユーザーを返します。パスワードは返されません

POST /auth/login

認証を行い、24時間有効な署名済みJWTを受け取ります。

{ "username": "alice", "password": "hunter2" }

{ "token": "<jwt>" } を返します。ユーザー名・パスワードのどちらが誤っていても 401 を返し、ユーザー名の列挙を防ぎます。

POST /auth/challenge-wallet

Solanaウォレットの所有権を証明するための署名チャレンジをリクエストします。有効なJWTが必要です。

メッセージ、ノンス、および有効期限を返します。チャレンジは10分で失効します。

{
"message": "PrivateChannel wallet verification\nuser: <uuid>\nnonce: <uuid>\nexpires: <unix>",
"nonce": "<uuid>",
"expires_at": "<iso8601>"
}

POST /auth/verify-wallet

署名済みチャレンジを送信して、ウォレットを検証済みとして登録します。有効なJWTが必要です。

{
"pubkey": "<base58 pubkey>",
"nonce": "<uuid from challenge>",
"signature": "<base58 Ed25519 signature>"
}

サービスはチャレンジメッセージを再構築し、Ed25519署名を検証してウォレットを保存します。各ノンスは一度しか使用できず、リプレイは拒否されます。

{ "pubkey": "<base58>", "created_at": "<iso8601>" } を返します。

GET /auth/wallets

認証済みユーザーのすべての検証済みウォレットを一覧表示します。有効なJWTが必要です。

DELETE /auth/wallets/{pubkey}

認証済みユーザーのアカウントから検証済みウォレットを削除します。有効なJWTが必要です。

GET /health

死活確認。200 ok を返します。認証不要です。

JWT構造

トークンはHS256アルゴリズムを使用し、発行から24時間後に失効します。

クレーム値
subユーザーUUID
role"user" または "operator"
iss"private-channel-auth"
aud"private-channel-gateway"
expUnixタイムスタンプ(発行から24時間後)

iss と aud はJWTペイロードに含まれていますが、アプリケーションのクレーム構造体にデシリアライズされるのではなく、ゲートウェイのJWT設定によって検証されます。アプリケーション層のコードがアクセスできるのは sub、role、exp のみです。

Authorization ヘッダーにトークンを渡してください:

Authorization: Bearer <JWT_TOKEN>

ロール

user

登録時のデフォルトロール。

  • アクセスはユーザー自身の検証済みウォレットに限定されます
  • 制限対象:getBlock、getTransaction、simulateTransaction
  • 可能な操作:EscrowプログラムでのDepositの呼び出し、WithdrawFundsを通じた出金の開始

operator

昇格されたロール。直接プロビジョニングが必要で、userからoperatorへのセルフサービスの昇格パスは存在しません。

ロールの付与(Admin CLI private-channel-auth-admin を使用):

private-channel-auth-admin set-role --username alice --role operator

または直接SQLで:

これは特権的なデータベース操作です。Auth Serviceのデータベースへのアクセスを適切に制限し、ロール変更を監査してください。

UPDATE private_channel_auth.users SET role = 'operator' WHERE username = 'alice';

セルフ検証フローを経ずにウォレットを登録する(Admin CLI、private-channel-auth-admin):

private-channel-auth-admin attach-wallet --username alice --pubkey <base58-pubkey>

このコマンドは、チャレンジ/検証フローを経ずに、検証済みウォレットを verified_wallets テーブルに直接挿入します。(user_id, pubkey) に対するユニーク制約が適用されます。このコマンド単体では operator ロールは付与されません。ロールの付与には set-role または上記のSQLアップデートを使用してください。このコマンドは、インタラクティブなチャレンジ/検証フローを必要とせず、アカウント(例:サービスアカウント)にウォレットを紐付けるためのものです。

権限:

  • すべてのウォレット所有権チェックをバイパス
  • getBlock、getTransaction、simulateTransaction を含む、すべてのゲートウェイRPCメソッドへのフルアクセス
  • 必須対象:ReleaseFunds、ResetSmtRoot

完全な認証フロー

認証済みリクエストの実行

const response = await fetch("http://localhost:8899/", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${jwtToken}`
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getBalance",
params: [walletAddress]
})
});
const data = await response.json();

ゲートウェイエンドポイント

以下のエンドポイントは認証不要です:

エンドポイントメソッド説明成功失敗
/healthGET死活確認200 {"status":"ok"}-
/readyGET詳細な準備状態確認;書き込みノードと読み取りノードを検査200 {"status":"ready"}503 {"status":"degraded"}

JWT_SECRET およびゲートウェイ環境変数のリファレンスについては、設定リファレンスを参照してください。

RPCメソッドアクセスマトリクス

以下のメソッドはゲートウェイによって認識されます。JWT_SECRET が設定されている場合、アクセスはJWTロールによって異なります:

メソッドルートJWT なしuseroperator
sendTransaction書き込みノード✓✓✓
getLatestBlockhash読み取りノード✓✓✓
getSlot読み取りノード✓✓✓
getRecentBlockhash読み取りノード✓✓✓
getSignatureStatuses読み取りノード✓✓✓
getTransactionCount読み取りノード✓✓✓
getFirstAvailableBlock読み取りノード✓✓✓
getBlocks読み取りノード✓✓✓
getEpochInfo読み取りノード✓✓✓
getEpochSchedule読み取りノード✓✓✓
getRecentPerformanceSamples読み取りノード✓✓✓
getBlockTime読み取りノード✓✓✓
getVoteAccounts読み取りノード✓✓✓
getSupply読み取りノード✓✓✓
getSlotLeaders読み取りノード✓✓✓
isBlockhashValid読み取りノード✓✓✓
getAccountInfo読み取りノード401所有権ゲート¹✓
getTokenAccountBalance読み取りノード401所有権ゲート¹✓
getSignaturesForAddress読み取りノード401所有権ゲート¹✓
getBlock読み取りノード401403✓
getTransaction読み取りノード401403✓
simulateTransaction読み取りノード401403✓

¹ 所有権ゲート:SPL token account(ownerフィールドが TokenkegQ... または TokenzQ... で、データが165バイト以上)の場合、ゲートウェイは owner または delegate フィールドが認証済みユーザーの検証済みウォレットのいずれかと一致するかを確認します。それ以外のアカウントタイプ(System Program ウォレット、または不明なPDA)の場合は、そのようなアカウントには検査すべき owner/delegate フィールドがないため、クエリされた pubkey 自体がユーザーの検証済みウォレットの一つであるかどうかを確認します。いずれかのチェックが失敗した場合は403を返します。

Is this page helpful?

© 2026 Solana Foundation. 無断転載を禁じます。