Ktor 1.5.4 Help

JWT and JWK

Ktor supports JWT (JSON Web Tokens), which is a mechanism for authenticating JSON-encoded payloads. It is useful to create stateless authenticated APIs in the standard way, since there are client libraries for it in a myriad of languages.

This feature will handle Authorization: Bearer <JWT-TOKEN>.

Ktor has a couple of classes to use the JWT Payload as Credential or as Principal.

class JWTCredential(val payload: Payload) : Credential class JWTPrincipal(val payload: Payload) : Principal

Add dependencies

To enable JWT and JWK authentication, you need to include the ktor-auth and ktor-auth-jwt artifacts in the build script:

implementation "io.ktor:ktor-auth:$ktor_version" implementation "io.ktor:ktor-auth-jwt:$ktor_version"
implementation("io.ktor:ktor-auth:$ktor_version") implementation("io.ktor:ktor-auth-jwt:$ktor_version")
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-auth</artifactId> <version>${ktor_version}</version> </dependency> <dependency> <groupId>io.ktor</groupId> <artifactId>ktor-auth-jwt</artifactId> <version>${ktor_version}</version> </dependency>

Configuring server/routes

JWT and JWK each have their own method with slightly different parameters. Both require the realm parameter, which is used in the WWW-Authenticate response header.

Using a verifier and a validator

The verifier will use the secret to verify the signature to trust the source. You can also check the payload within validate callback to ensure everything is right and to produce a Principal.

application.conf:

jwt { domain = "https://jwt-provider-domain/" audience = "jwt-audience" realm = "ktor sample app" }

JWT auth

val issuer = environment.config.property("jwt.domain").getString() val audience = environment.config.property("jwt.audience").getString() val myRealm = environment.config.property("jwt.realm").getString() install(Authentication) { jwt("auth-jwt") { realm = myRealm verifier(JWT .require(Algorithm.HMAC256("secret")) .withAudience(audience) .withIssuer(issuer) .build()) validate { credential -> if (credential.payload.audience.contains(audience)) { JWTPrincipal(credential.payload) } else { null } } } }

Using a JWK provider

val jwkIssuer = environment.config.property("jwt.domain").getString() val jwkAudience = environment.config.property("jwt.audience").getString() val jwkRealm = environment.config.property("jwt.realm").getString() val jwkProvider = JwkProviderBuilder(jwkIssuer) .cached(10, 24, TimeUnit.HOURS) .rateLimited(10, 1, TimeUnit.MINUTES) .build() install(Authentication) { jwt("auth-jwk") { realm = jwkRealm verifier(jwkProvider, jwkIssuer) validate { credential -> if (credential.payload.audience.contains(jwkAudience)) { JWTPrincipal(credential.payload) } else { null } } } }

Last modified: 26 April 2021