jwt(ジェット)とは
JWT(JSON Web Token)認証は、JSON形式のトークンを使用してユーザーの認証と情報の伝達を行う仕組み。セッション管理や認可に使用されている。jwtトークン自体に署名がついているので内容が改竄されていないかを検証できる。
jwtのメリット
- サイズが小さいのでHTTPヘッダーに格納できる
- ペイロードにはユーザーに関する必要な情報がすべて含まれているので何度もDBに問い合わせなくても認証ができる
- Json形式なので、多くの言語でパースやマッピングがサポートされており、使いやすい
jwtの構造
jetは以下の3つの要素で構成されている。
- ヘッダー(Header)
- ペイロード(Payload)
- 署名(Signature)
上記3つの要素をそれぞれハッシュ化したものを.
で連結したものがjwtトークンと呼ばれる文字列になる。
以下のサイトでイメージを確認できる。
https://jwt.io/
ヘッダー
ヘッダーにはハッシュ化に使用するアルゴリズム情報やトークンのタイプなどの情報が含まれる。
以下はハッシュアルゴリズムとしてHS256
を用いること、トークンタイプはjwtという意味になる。
{
"alg": "HS256",
"typ": "JWT"
}
ペイロード
ペイロードにはユーザーに関する情報やトークンの有効期限、発行者情報などが含まれる。
ユーザー情報のことをまとめてクレーム(claim)という。暗号化されていない限り、秘密の情報を入れてはいけない。
{
"sub": "1234567890",
"name": "tarou",
"iat": 1516239022,
"exp": 1516242622
}
sub:トークンのサブジェクト(ユーザーIDなど)
name:ユーザーの名前
iat:トークンの発行時間
exp:トークンの有効期限
署名
ヘッダー、ペイロード、ヘッダーで指定されたハッシュ化アルゴリズム、シークレット(秘密鍵)を用いて署名を作成する。
これによって、内容が改竄されていないことが証明できる。
jwtのデバッガーツール
以下のツールでjwtトークンを生成したり、中身を見たりできる
https://jwt.io/#debugger-io
認証手順
- ユーザーがサーバーにユーザー名とパスワード(平文)を送信
- サーバーでjwtトークンを発行する
- クライアント側でトークンをローカルストレージやクッキーに保存
- 以降のリクエストでは、HTTPヘッダーにAuthorizationの値としてjwtトークンを入れてサーバーにリクエストを行う
- サーバーはAuthorizationのトークン内容を検証して正しければ、各種処理やAPIの実行に進む
GOでjwtトークンを作成する
"github.com/golang-jwt/jwt/v4"パッケージを使う
import (
"os"
"time"
jwt "github.com/golang-jwt/jwt/v4"
)
func Login(user User) (string, error) {
// ユーザーのリクエストをもとにユーザー情報がDBにあるか検索
// 省略
// パスワードの検証(DBにあるhash化されたパスワードとユーザーが送信してきた平文のパスワードを比較)
// 省略
//パスワードが一致した場合、jwtトークンを生成する
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": userId,
"exp": time.Now().Add(time.Hour * 24).Unix(), //jwtトークンの有効期限設定
})
//署名を作成してjwtトークン生成、SECRETは秘密鍵のことなので、環境変数にしておく
token, err := jwtToken.SignedString([]byte(os.Getenv("SECRET")))
if err != nil {
return "", err
}
// 完成したjwtトークンを返す
return token, nil
}
まとめ
- 自分の勤務先もjwtトークンを用いた認証が使われているが今回のアウトプットでjwtの外観を掴むことに成功したと思う。GOやJsを使用しているとjson形式自体のありがたみも痛感した。