Tokens JWT em Kotlin: guia completo com a biblioteca jjwt
\n\nNo desenvolvimento web moderno, os JWT (JSON Web Tokens) se tornaram o padrão para autenticação e troca de informações entre cliente e servidor. No ecossistema Kotlin, especialmente ao criar aplicações backend com Spring Boot ou Ktor, surge frequentemente a necessidade de trabalhar com JWT. Neste artigo, vamos explorar a biblioteca io.jsonwebtoken (jjwt) — a ferramenta mais popular para trabalhar com JWT em Java/Kotlin.
O que é JWT?
\nJWT é uma forma compacta e segura para URL de representar declarações (claims) entre duas partes. O token é composto por três partes, separadas por pontos:
\n- \n
- Header — cabeçalho contendo o tipo do token e o algoritmo de assinatura (ex.: HS256, RS256). \n
- Payload — carga útil com as declarações (claims):
sub(sujeito),iat(data de emissão),exp(data de expiração) e dados personalizados. \n - Signature — assinatura criada com uma chave secreta ou par de chaves. \n
Adicionando a biblioteca
\nPara trabalhar com JWT em Kotlin, usaremos jjwt (io.jsonwebtoken). Adicione a dependência no build.gradle.kts:
dependencies {\n implementation("io.jsonwebtoken:jjwt-api:0.12.6")\n runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")\n runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") // para parsing JSON\n}\n\nGeração de token JWT
\nPara criar um token, é necessário definir uma chave secreta, configurar as declarações e assinar o token. Exemplo em Kotlin:
\nimport io.jsonwebtoken.Jwts\nimport io.jsonwebtoken.security.Keys\nimport java.util.Date\nimport javax.crypto.SecretKey\n\nfun generateToken(userId: String, secret: String): String {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n \n val now = Date()\n val expiration = Date(now.time + 3600_000) // +1 hora\n \n return Jwts.builder()\n .subject(userId)\n .issuedAt(now)\n .expiration(expiration)\n .claim("role", "USER")\n .signWith(key)\n .compact()\n}\n\nVerificação e análise de JWT
\nAo receber um token do cliente, é necessário verificar sua assinatura e prazo de validade. Use Jwts.parser():
import io.jsonwebtoken.JwtException\nimport io.jsonwebtoken.Jwts\nimport io.jsonwebtoken.security.Keys\nimport javax.crypto.SecretKey\n\nfun validateToken(token: String, secret: String): Boolean {\n return try {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n Jwts.parser()\n .verifyWith(key)\n .build()\n .parseSignedClaims(token)\n true\n } catch (e: JwtException) {\n false\n }\n}\n\nfun extractUserId(token: String, secret: String): String? {\n return try {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n val claims = Jwts.parser()\n .verifyWith(key)\n .build()\n .parseSignedClaims(token)\n .payload\n claims.subject\n } catch (e: Exception) {\n null\n }\n}\n\nTrabalhando com claims personalizados
\nVocê pode adicionar quaisquer dados arbitrários ao payload. Por exemplo, armazenar email ou papel do usuário:
\nfun generateTokenWithCustomClaims(userId: String, email: String, secret: String): String {\n val key = Keys.hmacShaKeyFor(secret.toByteArray())\n \n return Jwts.builder()\n .subject(userId)\n .claim("email", email)\n .claim("isAdmin", false)\n .issuedAt(Date())\n .expiration(Date(System.currentTimeMillis() + 3600_000))\n .signWith(key)\n .compact()\n}\n\nfun extractCustomClaim(token: String, secret: String): String? {\n val key = Keys.hmacShaKeyFor(secret.toByteArray())\n