
JWT creation, decoding and verification using an auth0-compatible API; HMAC algorithms (HS256/384/512) plus unsecured "none", common-code-first design, source or JitPack consumption.
Create, sign, verify and decode JSON Web Tokens from common Kotlin code on every Kotlin Multiplatform target.
JWT-Kotlin is a Kotlin Multiplatform port of Auth0's java-jwt. It is pure Kotlin: no JVM-only APIs and no Java libraries. Hashing and HMAC come from the KotlinMania ports of the RustCrypto crates, hmac-kotlin and sha2-kotlin.
| Family | Targets |
|---|---|
| JVM | jvm |
| Android | Android library, androidNativeArm64, androidNativeX64
|
| Apple |
macosArm64, iosArm64, iosSimulatorArm64, tvosArm64, tvosSimulatorArm64, watchosDeviceArm64, watchosSimulatorArm64
|
| Linux and Windows |
linuxX64, linuxArm64, mingwX64
|
| Web |
js (browser and Node.js), wasmJs (browser and Node.js), wasmWasi
|
Apple x86_64 and 32-bit targets are not published.
The library is on Maven Central as io.github.kotlinmania:jwt-kmp.
// build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.kotlinmania:jwt-kmp:0.3.1")
}
}
}Or with a version catalog:
# gradle/libs.versions.toml
[versions]
jwtKmp = "0.3.1"
[libraries]
jwt-kmp = { module = "io.github.kotlinmania:jwt-kmp", version.ref = "jwtKmp" }commonMain.dependencies {
implementation(libs.jwt.kmp)
}| JWS | Factory | Description |
|---|---|---|
| HS256 | Algorithm.hmac256(secret) |
HMAC with SHA-256 |
| HS384 | Algorithm.hmac384(secret) |
HMAC with SHA-384 |
| HS512 | Algorithm.hmac512(secret) |
HMAC with SHA-512 |
| none | Algorithm.none() |
Unsecured token, for tests only |
Secrets can be a String or a ByteArray. RSA (RS256/384/512) and ECDSA
(ES256/384/512) are not available yet.
import io.github.kotlinmania.jwt.JWT
import io.github.kotlinmania.jwt.algorithms.Algorithm
import kotlin.time.Clock
import kotlin.time.Duration.Companion.hours
val algorithm = Algorithm.hmac256("super-secret")
val now = Clock.System.now()
val token: String =
JWT.create()
.withIssuer("auth.example.com")
.withSubject("user-42")
.withAudience("api.example.com")
.withIssuedAt(now)
.withExpiresAt(now + 1.hours)
.withClaim("role", "admin")
.sign(algorithm)verify checks the signature and every claim you require, and throws a
JWTVerificationException subtype when anything does not match.
import io.github.kotlinmania.jwt.exceptions.JWTVerificationException
import io.github.kotlinmania.jwt.exceptions.TokenExpiredException
val verifier =
JWT.require(algorithm)
.withIssuer("auth.example.com")
.withAudience("api.example.com")
.withClaim("role", "admin")
.acceptLeeway(5) // seconds of clock skew allowed for exp, nbf and iat
.build()
try {
val decoded = verifier.verify(token)
println("subject = ${decoded.subject}")
} catch (e: TokenExpiredException) {
// the token is past its exp claim
} catch (e: JWTVerificationException) {
// bad signature, wrong issuer or audience, missing claim, ...
}Custom checks take a predicate:
JWT.require(algorithm)
.withClaim("role") { claim, _ -> claim.asString() in setOf("admin", "owner") }
.build()Decoding only parses the token. Never trust the result for authorization.
import io.github.kotlinmania.jwt.exceptions.JWTDecodeException
try {
val decoded = JWT.decode(token)
println(decoded.algorithm) // "HS256"
println(decoded.getClaim("role").asString()) // "admin"
} catch (e: JWTDecodeException) {
// not a well-formed JWT
}| Registered claim | Accessor |
|---|---|
iss |
decoded.issuer |
sub |
decoded.subject |
aud |
decoded.audience |
exp / nbf / iat
|
decoded.expiresAt / decoded.notBefore / decoded.issuedAt (kotlin.time.Instant) |
jti |
decoded.id |
Any claim is available through decoded.getClaim(name), with asString(),
asInt(), asLong(), asDouble(), asBoolean(), asDate(), asList(...),
asMap() and isNull().
Apple consumers can use the XCFramework:
./gradlew assembleJWTKMPXCFrameworkThe framework is written to build/XCFrameworks/release/JWTKMP.xcframework.
./gradlew build # every target
./gradlew test # every test this host can run, plus the Swift Export smoke testIssues and pull requests are welcome. Please include a minimal reproduction and the target where the problem appears.
MIT. See LICENSE.
This Kotlin Multiplatform port was created by Sydney Renee of The Solace Project for KotlinMania.
Create, sign, verify and decode JSON Web Tokens from common Kotlin code on every Kotlin Multiplatform target.
JWT-Kotlin is a Kotlin Multiplatform port of Auth0's java-jwt. It is pure Kotlin: no JVM-only APIs and no Java libraries. Hashing and HMAC come from the KotlinMania ports of the RustCrypto crates, hmac-kotlin and sha2-kotlin.
| Family | Targets |
|---|---|
| JVM | jvm |
| Android | Android library, androidNativeArm64, androidNativeX64
|
| Apple |
macosArm64, iosArm64, iosSimulatorArm64, tvosArm64, tvosSimulatorArm64, watchosDeviceArm64, watchosSimulatorArm64
|
| Linux and Windows |
linuxX64, linuxArm64, mingwX64
|
| Web |
js (browser and Node.js), wasmJs (browser and Node.js), wasmWasi
|
Apple x86_64 and 32-bit targets are not published.
The library is on Maven Central as io.github.kotlinmania:jwt-kmp.
// build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.kotlinmania:jwt-kmp:0.3.1")
}
}
}Or with a version catalog:
# gradle/libs.versions.toml
[versions]
jwtKmp = "0.3.1"
[libraries]
jwt-kmp = { module = "io.github.kotlinmania:jwt-kmp", version.ref = "jwtKmp" }commonMain.dependencies {
implementation(libs.jwt.kmp)
}| JWS | Factory | Description |
|---|---|---|
| HS256 | Algorithm.hmac256(secret) |
HMAC with SHA-256 |
| HS384 | Algorithm.hmac384(secret) |
HMAC with SHA-384 |
| HS512 | Algorithm.hmac512(secret) |
HMAC with SHA-512 |
| none | Algorithm.none() |
Unsecured token, for tests only |
Secrets can be a String or a ByteArray. RSA (RS256/384/512) and ECDSA
(ES256/384/512) are not available yet.
import io.github.kotlinmania.jwt.JWT
import io.github.kotlinmania.jwt.algorithms.Algorithm
import kotlin.time.Clock
import kotlin.time.Duration.Companion.hours
val algorithm = Algorithm.hmac256("super-secret")
val now = Clock.System.now()
val token: String =
JWT.create()
.withIssuer("auth.example.com")
.withSubject("user-42")
.withAudience("api.example.com")
.withIssuedAt(now)
.withExpiresAt(now + 1.hours)
.withClaim("role", "admin")
.sign(algorithm)verify checks the signature and every claim you require, and throws a
JWTVerificationException subtype when anything does not match.
import io.github.kotlinmania.jwt.exceptions.JWTVerificationException
import io.github.kotlinmania.jwt.exceptions.TokenExpiredException
val verifier =
JWT.require(algorithm)
.withIssuer("auth.example.com")
.withAudience("api.example.com")
.withClaim("role", "admin")
.acceptLeeway(5) // seconds of clock skew allowed for exp, nbf and iat
.build()
try {
val decoded = verifier.verify(token)
println("subject = ${decoded.subject}")
} catch (e: TokenExpiredException) {
// the token is past its exp claim
} catch (e: JWTVerificationException) {
// bad signature, wrong issuer or audience, missing claim, ...
}Custom checks take a predicate:
JWT.require(algorithm)
.withClaim("role") { claim, _ -> claim.asString() in setOf("admin", "owner") }
.build()Decoding only parses the token. Never trust the result for authorization.
import io.github.kotlinmania.jwt.exceptions.JWTDecodeException
try {
val decoded = JWT.decode(token)
println(decoded.algorithm) // "HS256"
println(decoded.getClaim("role").asString()) // "admin"
} catch (e: JWTDecodeException) {
// not a well-formed JWT
}| Registered claim | Accessor |
|---|---|
iss |
decoded.issuer |
sub |
decoded.subject |
aud |
decoded.audience |
exp / nbf / iat
|
decoded.expiresAt / decoded.notBefore / decoded.issuedAt (kotlin.time.Instant) |
jti |
decoded.id |
Any claim is available through decoded.getClaim(name), with asString(),
asInt(), asLong(), asDouble(), asBoolean(), asDate(), asList(...),
asMap() and isNull().
Apple consumers can use the XCFramework:
./gradlew assembleJWTKMPXCFrameworkThe framework is written to build/XCFrameworks/release/JWTKMP.xcframework.
./gradlew build # every target
./gradlew test # every test this host can run, plus the Swift Export smoke testIssues and pull requests are welcome. Please include a minimal reproduction and the target where the problem appears.
MIT. See LICENSE.
This Kotlin Multiplatform port was created by Sydney Renee of The Solace Project for KotlinMania.