からんころんと技術探求

エンジニアの絵空事

ライブラリを利用せずにTypeScriptでJWT(JSON Web Token)をデコードする

モチベーション

認証基盤周りを触っていると頻出する、JWTのデコードですがライブラリのインストールが面倒なことも多いので作りました。(解説付き) ※ RFCを参照するとこのあたりはちゃんと書いています。

実際のコード

JSON Web Token サンプル

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

ArrayBuffer <=> string に相互変換するための便利関数

base64Url decodeの前に、
ArrayBuffer => string
string => ArrayBufferLike
の変換ための関数を用意する必要があります。

function arrayBufferToStr(arrayBuffer: ArrayBuffer): string {
    const uint16Array = new Uint16Array(arrayBuffer)
    const numberArray = Array.from(uint16Array).filter((b): b is number => typeof b === 'number')
    return String.fromCharCode.apply('', numberArray)
}

function strToArrayBufferLike(str: string): ArrayBufferLike {
    const numberArray= ([].map.call(str, (c: string) => {
        return c.charCodeAt(0)
    })).filter((b): b is number => typeof b === 'number')
    return new Uint16Array(numberArray).buffer
}

base64UrlDecode()関数

  1. base64Url文字列 を base64 decode するために "+" => "/", "_" => "-" に書き換えます。
  2. base64 decode 対象の文字列長が4の倍数以外の場合は、4の倍数になるように "=" でパディングします。
  3. atob()関数を利用して、base64 decodeします。
  4. 目的の状態になるように便利関数を利用してデータを変換します。
function base64UrlDecode(base64UrlStr: string): string {
    let str: string = base64UrlStr.replace('+', '/').replace('_', '-')
    if (str.length % 4 !== 0) {
        for (let i = 4 - str.length % 4; i === 0; i--) {
            str = str + '='
        }
    }
    // フォーマットしたbase64Url文字列 に対してデコードをかける
    const bufferStr = atob(base64UrlStr)
    return arrayBufferToStr(strToArrayBufferLike(bufferStr))
}

実行結果

JSON Web Tokenは各要素がピリオド区切りになっています。
<HEADER>.<PAYLOAD>.<VERIFY SIGNATURE>
VERIFY SIGNATURE の部分はハッシュ化されているのでデコードはできません。

const splits = JWT.split('.')
const header = splits[0]
const payload = splits[1]
const signature = splits[2]

console.log(JSON.parse(base64rlLDecode(header)))
// => {"alg":"HS256","typ":"JWT"}

console.log(JSON.parse(base64rlLDecode(payload)))
// => {"sub":"1234567890","name":"John Doe","iat":1516239022}
  • TS Playground

www.typescriptlang.org

最近読んだ技術系の記事について

GitHub Actionsにおける脅威と対策について

zenn.dev

業務で最近 GitHub Actionsを使ってるけど、セキュリティについてあまり意識してなかったなあ。

GitHubアカウント自体の権限の話については考えることは当たり前になっていたのでアカウント乗っ取りなどはおいておいておく。依存関係のあるモジュールを実行する際、Self Hosted Runner上の実行権限などを緩めている場合とかに、不正なコードを実行しかねないなあと思ったりした。

あと、CI/CD で GitHub Actionsをフル活用していくなら、Actions用のセキュリティ目的のリンタやリポジトリの設定などは、確認する必要がありそうかもって思った。

カスタマーサポートだけど、開発チームに敬意が持てない

anond.hatelabo.jp

これはけっこう前に見かけてた記事で前にも読んだことがあったけど、前職が似たような環境だった。
大概、プロジェクトマネージャーとかが迷走してるんだよね。開発方針そのものがよくないんだと思う。

いいものを作ること以上に何を作らないかを決めることは大事なんだけど、開発者がそれに振り回されている状況は誰も幸せになれないね...。
という感想でした。

TypeScriptを活用したi18n対応

speakerdeck.com

i18n対応、ちょうど1年前くらいにようやく概念を知ったんだけど、i18n って internationalization の略みたい。
型安全って書いてなくて丁寧!
型安全って言葉は、型システム入門 を読んでから安易に使わないようになっちゃった。
確かに、型がちゃんとついてると参照先の文言との関係性が明確になっていいかも。
カスタムESLintを作ってるの純粋にすごい。

ブログを開設しました

自己紹介

都内メーカー系の会社でソフトウェアエンジニアをしています。 主に認証基盤周りのことをやっていますが、得意なのはフロントエンド技術です。 基本的には雑多な技術に関連することを書いていきます。

実績とか

執筆とか

  • zenn

zenn.dev

  • Speaker Deck

speakerdeck.com

登壇

TSKaigi 2024 登壇

tskaigi.org

v-tokyo 20 登壇

vuejs-meetup.connpass.com

副業

企業サイトをリニューアルしたり

www.waoh.co.jp