JWT токены в Kotlin: генерация, проверка и использование с io.jsonwebtoken

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

JWT токены в Kotlin: полное руководство с библиотекой jjwt

В современной веб-разработке JWT (JSON Web Tokens) стали стандартом для аутентификации и обмена информацией между клиентом и сервером. В экосистеме Kotlin, особенно при создании бэкенд-приложений на Spring Boot или Ktor, часто возникает необходимость работать с JWT. В этой статье мы разберём библиотеку io.jsonwebtoken (jjwt) — самый популярный инструмент для работы с JWT в Java/Kotlin.

Что такое JWT?

JWT — это компактный, URL-безопасный способ представления утверждений (claims) между двумя сторонами. Токен состоит из трёх частей, разделённых точками:

  • Header — заголовок, содержащий тип токена и алгоритм подписи (например, HS256, RS256).
  • Payload — полезная нагрузка с утверждениями (claims): sub (субъект), iat (время выпуска), exp (время истечения) и пользовательские данные.
  • Signature — подпись, созданная с помощью секретного ключа или пары ключей.

Подключение библиотеки

Для работы с JWT в Kotlin мы будем использовать jjwt (io.jsonwebtoken). Добавьте зависимость в build.gradle.kts:

dependencies {
    implementation("io.jsonwebtoken:jjwt-api:0.12.6")
    runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")
    runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") // для JSON парсинга
}

Генерация JWT токена

Для создания токена необходимо задать секретный ключ, установить утверждения и подписать токен. Пример на Kotlin:

import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import java.util.Date
import javax.crypto.SecretKey

fun generateToken(userId: String, secret: String): String {
    val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())
    
    val now = Date()
    val expiration = Date(now.time + 3600_000) // +1 час
    
    return Jwts.builder()
        .subject(userId)
        .issuedAt(now)
        .expiration(expiration)
        .claim("role", "USER")
        .signWith(key)
        .compact()
}

Проверка и парсинг JWT

При получении токена от клиента необходимо проверить его подпись и срок действия. Используйте Jwts.parser():

import io.jsonwebtoken.JwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import javax.crypto.SecretKey

fun validateToken(token: String, secret: String): Boolean {
    return try {
        val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())
        Jwts.parser()
            .verifyWith(key)
            .build()
            .parseSignedClaims(token)
        true
    } catch (e: JwtException) {
        false
    }
}

fun extractUserId(token: String, secret: String): String? {
    return try {
        val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())
        val claims = Jwts.parser()
            .verifyWith(key)
            .build()
            .parseSignedClaims(token)
            .payload
        claims.subject
    } catch (e: Exception) {
        null
    }
}

Работа с кастомными claims

Вы можете добавлять любые произвольные данные в payload. Например, хранить email или роль пользователя:

fun generateTokenWithCustomClaims(userId: String, email: String, secret: String): String {
    val key = Keys.hmacShaKeyFor(secret.toByteArray())
    
    return Jwts.builder()
        .subject(userId)
        .claim("email", email)
        .claim("isAdmin", false)
        .issuedAt(Date())
        .expiration(Date(System.currentTimeMillis() + 3600_000))
        .signWith(key)
        .compact()
}

fun extractCustomClaim(token: String, secret: String): String? {
    val key = Keys.hmacShaKeyFor(secret.toByteArray())
    val claims = Jwts.parser()
        .verifyWith(key)
        .build()
        .parseSignedClaims(token)
        .payload
    return claims.get("email", String::class.java)
}

Использование в Spring Boot

В реальных проектах удобно создать сервисный класс для работы с JWT. Пример с инъекцией секрета из конфигурации:

import org.springframework.stereotype.Component
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import java.util.Date
import javax.crypto.SecretKey

@Component
class JwtService(private val jwtSecret: String) {
    
    private val key: SecretKey = Keys.hmacShaKeyFor(jwtSecret.toByteArray())
    
    fun generateToken(userId: String): String {
        return Jwts.builder()                    

Рекомендаций