技術ブログ

プログラミング、IT関連の記事中心

ライブラリを使用せずにJWT(JSON Web Token)をデコードする方法【Swift】

■はじめに

APIなどでJWTを取得する事があります。
その際にそのJWTをデコードして値を操作する必要があるので、ここでは「ライブラリを使用せずに」JWTをデコードする方法を記載します。
※ライブラリ使ってはいけないプロジェクトもあるので。。。

■手順

以下の関数を定義します。
細かい内容はコメントをみてください!!

/// JWT(Json Web Token)のデコード処理
/// - Parameters:
///   - token: JWT
///   - type: デコードタイプ(0: ヘッダーの取得, 1: ペイロードの取得)※引数に指定しなければペイロードが取得される
func jwtDecode(_ token: String, _ type: Int = 1) -> [String: AnyObject]? {
    // JWTを「.」で分割して取得したい項目を取得する(0:Header, 1:Payload)
    let toDecode = token.components(separatedBy: ".")[type] as String

    // JWTでエンコードする際にキャストされる文字列(「-」「+」)をキャスト前に戻す
    var stringtoDecode: String = toDecode.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
    // 文字数に応じて末に「=」を追加する
    switch stringtoDecode.utf16.count % 4 {
    case 2:
        stringtoDecode += "=="
    case 3:
        stringtoDecode += "="
    default:
        break
    }

    // JWTを辞書型にキャストする
    guard
        let dataToDecode = Data(base64Encoded: stringtoDecode, options: []),
        let base64DecodedString = NSString(data: dataToDecode, encoding: String.Encoding.utf8.rawValue),
        let data = base64DecodedString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: true),
        let value = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: AnyObject]
    else {
        // キャストが失敗したらnilを返す
        return nil
    }

    // キャストが正常に完了したらそのデータを返す
    return value
}

使い方の説明をする前に、テストでは以下のJWTを利用します。
※こちらのサイト様(https://jwt.io/)のデフォルト値のデータを拝借(感謝!)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

以下、JWTの値(PAYLOAD)の取得方法です。

let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
print(jwtDecode(jwt))

ちなみに、以下の様に記載しても同じです!!
※第二引数に「1」を入れました(デフォルト値が1なので入れなくてもいいですが。。。)

let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
print(jwtDecode(jwt, 1))

JWTのHEADERを取得したい場合には以下のように記載してください。
※第二引数が「0」です!

let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
print(jwtDecode(jwt, 0))

注意ですが、第二引数に「0」「1」以外を入れても「nil」が返ってくるだけです。