JWT токены в Swift (iOS/macOS): Полное руководство
JSON Web Token (JWT) — это открытый стандарт (RFC 7519) для создания токенов доступа, основанных на JSON. JWT широко используется для аутентификации и обмена информацией между клиентом и сервером. В экосистеме Apple (iOS, macOS, watchOS, tvOS) работа с JWT становится критически важной при разработке приложений, взаимодействующих с REST API, микросервисами или любыми системами, требующими безопасной передачи данных.
Данная статья посвящена библиотеке SwiftJWT — самому популярному и активно поддерживаемому решению для работы с JWT на языке Swift. Мы рассмотрим установку, базовые операции (создание, подпись, верификация) и продвинутые сценарии использования.
Что такое SwiftJWT?
SwiftJWT — это легковесная, нативная библиотека для Swift, которая позволяет:
- Создавать JWT с произвольными claims (утверждениями)
- Подписывать токены с использованием алгоритмов: HS256, HS384, HS512 (симметричные) и RS256, RS384, RS512 (асимметричные, на базе RSA)
- Верифицировать подпись и срок действия токена
- Декодировать payload без проверки подписи (например, для отображения информации на клиенте)
- Работать с кастомными данными и стандартными полями (iss, sub, exp, iat и др.)
Библиотека написана полностью на Swift, не требует внешних зависимостей (кроме Foundation и Security) и совместима с Swift Package Manager (SPM), CocoaPods и Carthage.
Установка через Swift Package Manager
Добавьте пакет в ваш проект через Xcode или напрямую в Package.swift:
// Package.swift
dependencies: [
.package(url: "https://github.com/Kitura/Swift-JWT.git", from: "4.0.0")
],
targets: [
.target(name: "YourTarget", dependencies: ["SwiftJWT"])
]
Базовые операции с JWT
1. Создание и подпись токена (HS256)
Самый простой случай — создание токена с использованием симметричного ключа:
import SwiftJWT
// 1. Определяем структуру Claims (утверждений)
struct MyClaims: Claims {
let iss: String
let sub: String
let exp: Date
let admin: Bool
let customData: String
}
// 2. Создаем экземпляр Claims
let claims = MyClaims(
iss: "com.yourcompany.app",
sub: "user123",
exp: Date(timeIntervalSinceNow: 3600), // +1 час
admin: true,
customData: "some_value"
)
// 3. Определяем ключ (для HS256 — любая строка)
let secretKey = "your-256-bit-secret".data(using: .utf8)!
// 4. Создаем JWT
var jwt = JWT(claims: claims)
let signedJWT = try jwt.sign(using: .hs256(key: secretKey))
print("Созданный токен:\n\(signedJWT)")
2. Верификация и декодирование токена
// Верификация с проверкой подписи и срока действия
let receivedToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
do {
// Верифицируем и декодируем
let verifiedJWT = try JWT<MyClaims>.verify(token: receivedToken, using: .hs256(key: secretKey))
print("Токен валиден. Claims: \(verifiedJWT.claims)")
// Проверяем конкретные поля
if verifiedJWT.claims.admin {
print("Пользователь является администратором")
}
} catch {
print("Ошибка верификации: \(error)")
// Возможные ошибки: expiredToken, invalidSignature, malformedToken
}
// Декодирование без верификации (только для чтения данных)
if let payload = try? JWTDecoder().decodePayload(from: receivedToken) {
print("Payload (без проверки): \(payload)")
}
3. Работа с асимметричными ключами (RS256)
Для production-сред рекомендуется использовать асимметричное шифрование (RSA). Сервер подписывает токен приватным ключом, а клиент верифицирует публичным:
// Генерация ключей (обычно выполняется на сервере)
let privateKey = """
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----
"""
let publicKey = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
"""
// Подпись на клиенте (если клиент имеет приватный ключ)
let privateKeyData = privateKey.data(using: .utf8)!
let jwtWith