会員連携の署名仕様
会員連携の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行を作ります。値はUTF-8のバイト列を小文字の16進数で書いたものです。 uchat-v2のあとに、3の行を改行(\n)1つずつでつなげます。- 4の文字列について、チャットルームのトークンを鍵としてHMAC-SHA256を計算します。小文字16進数64文字の前に
v2.を付けたものがhashです。 - 同じ順番で
名前 + 空白 + 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 の属性)でその都度取得してください。エラー別の対処は会員連携をご覧ください。
読んでもよくわからない場合は お問い合わせ掲示板に質問を書き込んでください。