📝

JWTのデコードを自作してみた

2024/05/15に公開

はじめに

フロント側での認証ロジックでJWTを扱いたく、TypeScriptを使ってJWTをデコードする関数を自作してみました。この関数は、エンコードされたJWTを受け取り、そのペイロードをJSONオブジェクトとして解読します。

実装コード

以下がJWTのデコードを行うTypeScriptの関数です。

export const decodeJWT = (token: string): { [key: string]: any } | null => {
  try {
    const base64Url = token.split('.')[1]
    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
    const jsonPayload = decodeURIComponent(
      atob(base64)
        .split('')
        .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
        .join('')
    )
    return JSON.parse(jsonPayload)
  } catch (e) {
    return null
  }
}

入力例と出力例

以下はこの関数を使用した時の簡単な例です。

入力:

JWTトークン(短縮形): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvb G4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

出力:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

この例では、標準のJWTトークンが与えられ、そのペイロード部分がデコードされてJSON形式で出力されています。これにより、トークンに含まれる情報がどのように保持されているかが一目でわかります。

解説

JWTは.で区切られた3部分から構成されています。この関数では、まず2番目の部分(ペイロード)を取り出しています。ペイロードはBase64Urlエンコードされているため、これを通常のBase64形式に変換し、さらに文字列としてデコードしています。

atob()関数を使用してBase64文字列をデコードした後、各文字をURLエンコーディングされた16進数表現に変換し、それをデコードしてJSONオブジェクトを生成しています。エラーハンドリングもしており、何らかのエラーが発生した場合はnullを返します。

注意点

この関数はペイロードのデコードのみを行いますので、トークンの検証(署名の確認等)は行いません。実際のアプリケーションで使用する場合は、適切なJWTの検証を行いましょう。

まとめ

自作関数を作成することで、JWTの仕組みをより深く理解することができそうです。
実際にはライブラリを使っちゃう方が早いのでそちらも参考にしてみてください。

https://www.npmjs.com/package/jwt-decode

参考

https://zenn.dev/mikakane/articles/tutorial_for_jwt

Discussion