会員連携の署名仕様

会員連携のuser_data文字列のフィールド、署名(hash)の作り方、時刻連携のチェック、検証用の固定値です。

最終更新 2026年10月19日

このページ

会員連携の user_data は、自分のサーバーが会員情報にチャットルームのトークンで署名した文字列です。このページは、フィールド、署名の手順、サーバーがチェックするルールの正式な仕様です。導入の流れと言語別のサンプルは会員連携をご覧ください。

フィールド

次のフィールドのうち値のあるものだけが署名に入ります。署名はフィールド名の順番で行うので、入れる順番は関係ありません。署名コードは入れたフィールドをすべて署名するため、この表にないフィールドを入れるとエラー202になります。今後フィールドが増えても、新しいフィールドを入れないサイトの署名は変わりません。

フィールド 形式 説明
auth 0〜3 または guest、member、subadmin、admin 権限。0 ゲスト、1 会員、2 モデレーター、3 管理者。空にすると、id があれば会員、なければゲスト
icons URLのリスト ニックネームの横のアイコン。カンマで複数指定でき、@ より前はニックネームの前、後ろはニックネームの後ろに表示されます。例: /img/a.png,/img/b.png@/img/c.png
id 文字列 会員ID。BAN・ミュート・権限付与の基準になります
level 数値 レベル。チャットルームの機能の条件でレベルを比較するときに使われます
nick 文字列 ニックネーム。サーバーが15文字で切ったあと、空白を取り除きます
nickcon URL ニックネームの代わりに表示する画像
other 文字列 追加表示。単語は半角スペース1つで区切ります。通常は空にしておきます
room チャットルームID 必須。<u-chat room> の値と同じである必要があります
time Unix時刻(秒) 必須。署名を作成した現在時刻。時刻連携をオフにするとチェックされませんが、常に入れてください

署名の鍵はチャットルームのトークンです。トークンは管理ページのチャットルーム情報 → トークンで確認でき、結果の文字列には含めません。サーバーREST APIのAPIキーとは別の値です。トークンが漏れると誰でも管理者として入室できるため、サーバーのコードにだけ置いてください。

署名の手順

  1. 値のあるフィールドだけを選びます。空の値と入れていないフィールドは除き、トークンも入れません。
  2. フィールドを名前順(英小文字、バイト順)に並べます。
  3. フィールドごとに 名前=値 の1行を作ります。値はUTF-8のバイト列を小文字の16進数で書いたものです。
  4. uchat-v2 のあとに、3の行を改行(\n)1つずつでつなげます。
  5. 4の文字列について、チャットルームのトークンを鍵としてHMAC-SHA256を計算します。小文字16進数64文字の前に v2. を付けたものが hash です。
  6. 同じ順番で 名前 + 空白 + encodeURIComponent(値) を | でつなぎ、最後に hash 値 を付けます。

結果の形:

icons ...|id ...|level ...|nick ...|room my-room|time 1700000000|hash v2.0123...(64文字)
  • 値はJavaScriptの encodeURIComponent と同じようにエンコードします。空白は %20 です。PHPでは rawurlencode を使います。rawurlencode のように ~、*、! などを余分にエンコードしても、デコードすれば同じ値なのでhashは同じです。
  • チャット画面は各値を decodeURIComponent でデコードしてサーバーに送り、サーバーは同じ順番でhashを再計算して比較します。hash の16進数は大文字・小文字を区別しません。
  • HMAC-SHA256と16進数変換は、ほとんどの言語の標準ライブラリにあります(PHP 5.6以上の hash_hmac・bin2hex、Node.jsの crypto、Pythonの hmac・hashlib、Javaの javax.crypto.Mac、C#の HMACSHA256、Goの crypto/hmac、Rubyの OpenSSL::HMAC)。

参考実装(Node.js):

const crypto = require('node:crypto');

function signUserData(user, token) {
	const fields = Object.entries({ ...user, time: Math.floor(Date.now() / 1000) })
		.filter(([, v]) => v !== undefined && v !== null && v !== '')
		.map(([k, v]) => [k, String(v)])
		.sort(([a], [b]) => (a < b ? -1 : 1));
	const message = ['uchat-v2', ...fields.map(([k, v]) => k + '=' + Buffer.from(v, 'utf8').toString('hex'))].join('\n');
	const hash = crypto.createHmac('sha256', token).update(message, 'utf8').digest('hex');
	return fields
		.map(([k, v]) => k + ' ' + encodeURIComponent(v))
		.concat('hash v2.' + hash)
		.join('|');
}

// signUserData({ room: 'my-room', nick: '홍길동', id: 'user1', level: 5 }, process.env.UCHAT_TOKEN)

検証用の固定値

自分で書いたコードが正しいかどうか、次の入力で確認してください。同じ結果になるはずです。

入力 値
トークン test-token-1234
time 1700000000
room my-room
nick 홍 길동~*!
id user@example.com
level 5
auth (空の値)
icons /img/a.png,/img/b.png@/img/c.png

HMACに渡す文字列(手順4。空の値の auth は行がありません):

uchat-v2
icons=2f696d672f612e706e672c2f696d672f622e706e67402f696d672f632e706e67
id=75736572406578616d706c652e636f6d
level=35
nick=ed998d20eab8b8eb8f997e2a21
room=6d792d726f6f6d
time=31373030303030303030

結果の user_data:

icons %2Fimg%2Fa.png%2C%2Fimg%2Fb.png%40%2Fimg%2Fc.png|id user%40example.com|level 5|nick %ED%99%8D%20%EA%B8%B8%EB%8F%99~*!|room my-room|time 1700000000|hash v2.80d95cf251e7aeef90b37547dbe95ef5336f6c7f8cb235a6cf6cee91031e2ae6

auth は空なので、user_data と署名の両方から省かれました。PHPの rawurlencode で作ると ~、*、! が %7E、%2A、%21 になり、文字列は変わりますが hash は同じで、そのまま動作します。

サーバーのチェック

会員連携をオンにしたチャットルームでは、入室時にチャットサーバーが次の順番でチェックします。

チェック 失敗時のエラー
hash があるか 203
hashが正しいか(上の手順で再計算) 202
時刻連携がオンなら、time が基準より古くなく、同じ署名を最初に使ってから300秒が経っていないか 205

署名には使い捨ての値(nonce)がありません。時刻連携をオフにすると、一度作った user_data をコピーしていつでも再利用できてしまうため、時刻連携はオンにしておいてください。

時刻連携

管理ページの会員連携画面で時刻連携をオンにしたときだけ time をチェックします。オフにすると time は署名に含まれるだけで、値はチェックされません。

  • offset = time - uchat サーバーの現在時刻 を計算します。
  • 保存された基準がなければ、今回の offset を基準として保存します(初回接続)。
  • 基準があり、offset が基準より 300秒を超えて小さい場合(古い接続情報)は、エラー205で拒否します。未来の時刻はブロックしません。
  • 同じ hash は、チャットサーバーが最初に受け取ってから300秒間だけ受け付けます。それ以降はエラー205です。
  • 初めて受け取る hash で通過したときだけ、基準を今回の offset に更新します。同じ user_data を再利用しても基準は動きません。
  • 標準時刻に固定をオンにすると基準を0にします。time がuchatサーバーの時刻より300秒を超えて過去なら拒否します。自分のサーバーの時計が正確な場合に使ってください。
  • 自分のサーバーを移転した場合や、時計を300秒を超えて巻き戻した場合は、管理ページで時刻基準を初期化します。
  • 時刻連携をオンにしたチャットルームで time が数値でない場合はエラー101です。

user_data をページにキャッシュしておくと、5分後からエラー205が出ることがあります。会員連携のページはキャッシュしないか、user_data_url(u-chat の属性)でその都度取得してください。エラー別の対処は会員連携をご覧ください。

読んでもよくわからない場合は お問い合わせ掲示板に質問を書き込んでください。

商号 UCHAT · 代表者 김경욱 · 事業者登録番号 141-05-32832
所在地 경기도 파주시 와석순환로 61 · 通信販売業届出番号 2013-경기파주-4485호
代表電話 010-8677-8633 · メール support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.