SwiftJWT
認証ライブラリ
SwiftJWT
概要
SwiftJWTは、IBMが開発したSwift言語用のJSON Web Token(JWT)実装ライブラリです。iOS、macOS、Linux環境でJWTの作成、署名、検証を行うことができ、様々な署名アルゴリズムをサポートしています。軽量で高性能なセキュアなトークン認証システムを構築するのに適しています。
詳細
SwiftJWTは、RFC 7519に準拠したJWTの完全な実装を提供します。JWTの生成からトークンの検証まで、認証に必要な全ての機能を包含しており、特にサーバーサイドSwiftアプリケーションでの使用に最適化されています。
主要コンポーネント
- JWT構造体: ヘッダーとクレームを含むJWTの表現
- Claims: RFC 7519で定義された標準クレーム(ClaimsStandardJWT)
- JWTSigner: 署名アルゴリズムを管理する構造体
- JWTVerifier: トークンの検証機能
サポートされる署名アルゴリズム
- RSA: RS256, RS384, RS512
- ECDSA: ES256, ES384, ES512
- HMAC: HS256, HS384, HS512
- なし(none): 未署名トークン(開発用)
セキュリティ機能
- デジタル署名による改ざん検知
- 有効期限(exp)クレームによる時間制限
- 発行者(iss)や対象者(aud)の検証
- カスタムクレームのサポート
メリット・デメリット
メリット
- 完全なSwift実装: ネイティブSwiftコードで高いパフォーマンス
- クロスプラットフォーム: iOS、macOS、Linuxで動作
- 標準準拠: RFC 7519完全対応
- 多様なアルゴリズム: 複数の署名アルゴリズムサポート
- 型安全: Swiftの型システムを活用した安全な実装
- IBM サポート: Kituraチームによる保守
デメリット
- JWE非対応: JWS(署名)のみサポート、暗号化(JWE)は未対応
- 平文データ: クレームは Base64 エンコードのみで暗号化されない
- Swift限定: Swift以外の言語では使用不可
- 学習コスト: JWT の概念理解が必要
参考ページ
- SwiftJWT GitHub - 公式リポジトリ
- Kitura JWT Documentation - JWT認証ガイド
- Swift Package Index - パッケージ情報
書き方の例
パッケージ導入
// Package.swift
dependencies: [
.package(url: "https://github.com/Kitura/Swift-JWT.git", from: "3.6.200")
],
targets: [
.target(
name: "YourTarget",
dependencies: ["SwiftJWT"]
)
]
基本的なクレーム定義
import SwiftJWT
// カスタムクレーム構造体
struct MyClaims: Claims {
let sub: String // subject(ユーザーID)
let exp: Date // expiration(有効期限)
let iat: Date // issued at(発行時刻)
let iss: String // issuer(発行者)
let name: String // カスタムクレーム
let admin: Bool // カスタムクレーム
}
JWT生成と署名
import SwiftJWT
import Foundation
// HSアルゴリズム用のシークレット
let secret = "your-secret-key".data(using: .utf8)!
let signer = JWTSigner.hs256(key: secret)
// クレーム作成
let claims = MyClaims(
sub: "user123",
exp: Date(timeIntervalSinceNow: 3600), // 1時間後に期限切れ
iat: Date(),
iss: "myapp.com",
name: "John Doe",
admin: false
)
// JWT作成
let jwt = JWT(claims: claims)
// 署名付きトークン生成
do {
let signedJWT = try jwt.sign(using: signer)
print("Signed JWT: \(signedJWT)")
} catch {
print("Error signing JWT: \(error)")
}
JWT検証
// JWT文字列をデコードして検証
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
do {
// JWTをデコード
let jwt = try JWT<MyClaims>(jwtString: jwtString)
// 署名を検証
let verifier = JWTVerifier.hs256(key: secret)
let isValid = jwt.verify(using: verifier)
if isValid {
print("JWT is valid")
print("User: \(jwt.claims.name)")
print("Admin: \(jwt.claims.admin)")
// 有効期限チェック
if jwt.claims.exp > Date() {
print("Token is not expired")
} else {
print("Token has expired")
}
} else {
print("JWT signature is invalid")
}
} catch {
print("Error verifying JWT: \(error)")
}
RSA署名アルゴリズム使用例
import SwiftJWT
// RSA秘密鍵(PKCS#8形式)
let privateKeyPEM = """
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7...
-----END PRIVATE KEY-----
"""
// RSA公開鍵
let publicKeyPEM = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5...
-----END PUBLIC KEY-----
"""
// RSA256署名者と検証者を作成
let signer = JWTSigner.rs256(privateKey: privateKeyPEM.data(using: .utf8)!)
let verifier = JWTVerifier.rs256(publicKey: publicKeyPEM.data(using: .utf8)!)
// JWT作成と署名
let jwt = JWT(claims: claims)
let signedToken = try jwt.sign(using: signer)
// 検証
let decodedJWT = try JWT<MyClaims>(jwtString: signedToken)
let isValid = decodedJWT.verify(using: verifier)
標準クレーム使用例
// 標準的なJWTクレーム
struct StandardClaims: Claims {
let iss: String? // issuer
let sub: String? // subject
let aud: [String]? // audience
let exp: Date? // expiration
let nbf: Date? // not before
let iat: Date? // issued at
let jti: String? // JWT ID
}
let standardClaims = StandardClaims(
iss: "myapp.com",
sub: "user123",
aud: ["api.myapp.com"],
exp: Date(timeIntervalSinceNow: 3600),
nbf: Date(),
iat: Date(),
jti: UUID().uuidString
)
エラーハンドリング
// 包括的なエラーハンドリング
func processJWT(_ tokenString: String) {
do {
let jwt = try JWT<MyClaims>(jwtString: tokenString)
let verifier = JWTVerifier.hs256(key: secret)
guard jwt.verify(using: verifier) else {
print("Invalid signature")
return
}
guard jwt.claims.exp > Date() else {
print("Token expired")
return
}
print("Valid token for user: \(jwt.claims.name)")
} catch JWTError.invalidJWTString {
print("Invalid JWT format")
} catch JWTError.failedVerification {
print("Signature verification failed")
} catch {
print("Unexpected error: \(error)")
}
}