CryptoKitでJWTを作成する
はじめに
iOSでJWTの生成を行う場合Swift-JWTが一般的なのかと思いますが、依存関係がかなり複雑で入れたくなかったので自分で作れないか試してみました。
jwt.ioを使って正しくJWTの作成ができているのか確認しました、decodeする際も使いましたがめっちゃ便利なサイトで感謝🙏
JWTの生成
jwt.ioを開くとアルゴリズムを選択してDecodedの中身を弄るとEncodedされたJWTがリアルタイムで切り替わります。
今回は以下の初期値の値を使用してEncodedの値と一致するJWTを作成しました。
JWTのデータをEncodeする際+は-に、/は_に置き換えられます、そして4で割り切れない箇所は=で穴埋めされるという仕様があるのでencodeした値をurlSafeBase64EncodedStringで置き換えを行います。
import UIKit
import CryptoKit
extension Data {
func urlSafeBase64EncodedString() -> String {
return base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
}
struct Header: Encodable {
let alg = "HS256"
let typ = "JWT"
}
struct Payload: Encodable {
let sub = "1234567890"
let name = "John Doe"
let iat = 1516239022
}
enum JWTGenerator {
static func create(header: Header, payload: Payload, secret: String) -> String {
let privateKey = SymmetricKey(data: Data(secret.utf8))
let headerJSONData = try! JSONEncoder().encode(header)
let headerBase64String = headerJSONData.urlSafeBase64EncodedString()
let payloadJSONData = try! JSONEncoder().encode(payload)
let payloadBase64String = payloadJSONData.urlSafeBase64EncodedString()
let toSign = Data((headerBase64String + "." + payloadBase64String).utf8)
let signature = HMAC<SHA256>.authenticationCode(for: toSign, using: privateKey)
let signatureBase64String = Data(signature).urlSafeBase64EncodedString()
let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
return token
}
}
let token = JWTGenerator.create(header: Header(), payload: Payload(), secret: "your-256-bit-secret")
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
print(token)
参考文献
How do I generate a JWT to use in API authentication for Swift app