📝

【Go】JWTのペイロードから値を簡単に取り出す方法

に公開

はじめに

現在個人制作しているWebアプリケーションで、JWTのペイロードにあるidを取り出し認可チェックする実装をしました。
その中で、簡単にペイロードから値を簡単に取り出す方法を知ったので、備忘録的に書いていきます!

環境

  • go version go1.24.0 darwin/arm64

結論

JWTのクレームを取得し、jwt.MapClaims型に型アサーションする!

実装

main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    
    "github.com/golang-jwt/jwt/v5"
)

func handler(w http.ResponseWriter, r *http.Request) {
    secretKey := "example-secret-key"
    // テスト用JWTを生成
    testJwt, err := generateJWT(secretKey)
    if err != nil {
        return
    }
    // アルゴリズムと署名検証
    parsedToken, err := jwt.Parse(testJwt, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }
        return []byte(secretKey), nil
    })
    if err != nil || !parsedToken.Valid {
        return
    }
    claims, ok := parsedToken.Claims.(jwt.MapClaims)
    if !ok {
        return
    }
    user_id, ok := claims["user_id"].(string)
    if !ok {
        return
    }
    fmt.Println(user_id)
    // 出力結果:123
}

// テスト用のJWTを生成
func generateJWT(secretKey string) (string, error) {
    jwt := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user_id": "123",
    })
    signedJWT, _ := jwt.SignedString([]byte(secretKey))
    return signedJWT, nil
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

parsedToken.Claimsとは

パースしたトークンオブジェクトに格納されているクレーム(ペイロードに格納されている情報)です。
Claimsはjwt.Claimsインターフェース型で、実際にどんなデータが入っているかはわかりません。
このため、クレームの内容に応じて型を特定する必要があります。

jwt.MapClaimsとは

jwt.MapClaimsは、jwt.MapClaims型で、map[string]interface{}を指します。
型アサーションを行い、jwt.Claimsインターフェース型jwt.MapClaims型 に変換します。
キーをしているすることで値を取得することができます。

main.go
claims, ok := parsedToken.Claims.(jwt.MapClaims)
if !ok {
    return
}
user_id, ok := claims["user_id"].(string)
if !ok {
    return
}

まとめ

JWTのクレームを取得し、jwt.MapClaims型に型アサーションすることで、簡単に値を取り出すことができました!
最初はBase64URLエンコードされているものをデコードしていましたが、こちらの方がより簡単かつ安全に実装できているように感じます。

参考

Discussion