JWTとは
- 公式サイト
- JSON Web Tokenの略
- 電子署名により、改ざん検知できる。
- 認証用のトークンなどで用いられる。
構成
-
ヘッダ
、ペイロード
、署名
の3つから成る。 - それぞれは、
Base64
でエンコードされている - それぞれは、
. (ドット)
で結合されている。
[ヘッダ].
[ペイロード].
[署名]
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
t42p4AHef69Tyyi88U6+p0utZYYrg7mmCGhoAd7Zffs
作り方
1. アルゴリズム
とTokenのタイプ
を、ヘッダに設定
アルゴリズム | 説明 |
---|---|
HMAC SHA-256 | 256ビットのハッシュ値を生成する関数 |
{
"alg": "HS256",
"typ": "JWT"
}
2. ヘッダをBase64でエンコード
echo -n '{"alg":"HS256","typ":"JWT"}' | base64
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
3. ペイロードを設定
クレーム名 | 説明 |
---|---|
issued at | JWT を発行した時刻 |
subject | JWT の主語となる主体の識別子 |
{
"sub": "1234567890",
"iat": 1516239022
}
4. ペイロードをBase64でエンコード
echo -n '{"sub":"1234567890","iat":1516239022}' | base64
eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ
5. ヘッダとペイロードを . (ドット)
で結合し、署名なしTokenを生成
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ
6. 署名なしTokenに対し、秘密鍵とHMAC-SHA256を用いて署名を生成
echo -n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ' | \
openssl dgst -binary -sha256 -hmac 'secret' | \
base64
t42p4AHef69Tyyi88U6+p0utZYYrg7mmCGhoAd7Zffs
7. 署名なしTokenと署名を . (ドット)
で結合
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
t42p4AHef69Tyyi88U6+p0utZYYrg7mmCGhoAd7Zffs
実装
JWTの生成と検証を、Javascriptで実装する。
前提条件
秘密鍵の値を、secret
とする
JWTの生成
const crypto = require('crypto')
const base64 = json => {
const jsonStr = JSON.stringify(json)
const jsonB64 = Buffer.from(jsonStr).toString('base64')
const jsonB64NoPadding = jsonB64.replace(/={1,2}$/, '')
return jsonB64NoPadding
}
const HMAC_SHA256 = (key, data) => {
const hash = crypto.createHmac('sha256', key).update(data).digest('base64')
const hashNoPadding = hash.replace(/={1,2}$/, '')
return hashNoPadding
}
const header = { alg: 'HS256', typ: 'JWT' }
const payload = { sub: '1234567890', iat:1516239022 }
const key = 'secret'
const unsignedToken = `${base64(header)}.${base64(payload)}`
const signature = HMAC_SHA256(key, unsignedToken)
const jwt = `${unsignedToken}.${signature}`
console.log(jwt)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
t42p4AHef69Tyyi88U6+p0utZYYrg7mmCGhoAd7Zffs
JWTの検証
const crypto = require('crypto')
const HMAC_SHA256 = (key, data) => {
const hash = crypto.createHmac('sha256', key).update(data).digest('base64')
const hashNoPadding = hash.replace(/={1,2}$/, '')
return hashNoPadding
}
const key = 'secret'
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ.t42p4AHef69Tyyi88U6+p0utZYYrg7mmCGhoAd7Zffs'
const splits = jwt.split('.')
const unsignedToken = [splits[0], splits[1]].join('.')
const signature = splits[2]
console.log(HMAC_SHA256(key, unsignedToken) === signature)
true
認証におけるJWTの利用
新規登録/ログインより、ユーザはJWTを取得する。
APIを利用する際は、JWTを付与してリクエストを行う。
例として、JWTを利用し、ユーザ照会APIにリクエストを行う。
前提条件
- ペイロードは、ユーザIDと有効期限の情報をもつ
{
"user_id": "1234567890",
"iat": 1516239022
}
- APサーバは、以下のAPIを提供している。
Method | URL | Parameter | Response | 説明 |
---|---|---|---|---|
GET | /user | Authorization | ユーザ名を返す | ユーザ情報を返す |
Method | URL | Body | Response | 説明 |
---|---|---|---|---|
POST | /register | id, password | Tokenを返す | ユーザ登録を行う |
POST | /login | id, password | Tokenを返す | ログインを行う |
新規登録する場合
-
ユーザ登録
①name=hoge
,password=hoge
とし、/register
にPOSTリクエストする。
② APサーバは、DBに対し、新規登録をリクエストする。
③ DBは、ユニークなIDを設定しつつ、name
,password
の登録を行う。
④ DBは、APサーバに対し、ユーザIDを返す。
⑤ APサーバは、ユーザIDと秘密鍵より、Tokenを生成する。
⑥ APサーバは、ユーザにTokenを返す。
-
ユーザ情報をリクエスト
①Authorization
にJWTを設定し、/user
にGETリクエストする。
② APサーバは、秘密鍵を用いてTokenを検証する。
③ APサーバは、TokenからユーザIDを取得する。
④ APサーバは、DBに対し、IDに対するユーザ情報をリクエストする。
⑤ DBは、IDに対するユーザ情報を返す。
⑥ APサーバは、ユーザにユーザ情報を返す。
ログインする場合
-
ログイン
①name=hoge
,password=hoge
とし、/login
にPOSTリクエストする。
② APサーバは、DBに対し、ユーザの確認をリクエストする。
④ DBは、APサーバに対し、対応するユーザIDを返す。
⑤ APサーバは、ユーザIDと秘密鍵より、Tokenを生成する。
⑥ APサーバは、ユーザにTokenを返す。
-
ユーザ情報をリクエスト
①Authorization
にJWTを設定し、/user
にGETリクエストする。
② APサーバは、秘密鍵を用いてTokenを検証する。
③ APサーバは、TokenからユーザIDを取得する。
④ APサーバは、DBに対し、IDに対するユーザ情報をリクエストする。
⑤ DBは、IDに対するユーザ情報を返す。
⑥ APサーバは、ユーザにユーザ情報を返す。
まとめ
JWTを実装しました。実装することで、理解が深まると思います。
また、認証におけるJWTの利用方法についてまとめました。
間違い・指摘等があればコメントお願いします。