JWT and JWK authentication
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 itin a myriad of languages.
This feature will handle Authorization: Bearer <JWT-TOKEN>.
This feature is defined in the method io.ktor.auth.jwt.jwt in the artifact io.ktor:ktor-auth-jwt:$ktor_version.
dependencies { implementation "io.ktor:ktor-auth-jwt:$ktor_version"}
dependencies { implementation("io.ktor:ktor-auth-jwt:$ktor_version")}
<project> … <dependencies> <dependency> <groupId>io.ktor</groupId> <artifactId>ktor-auth-jwt</artifactId> <version>${ktor.version}</version> <scope>compile</scope> </dependency> </dependencies></project>
Ktor has a couple of classes to use the JWT Payload as Credential or as Principal.
1. class JWTCredential(val payload: Payload) : Credential
2. class JWTPrincipal(val payload: Payload) : Principal
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:
1. jwt {
2. domain = "https://jwt-provider-domain/"
3. audience = "jwt-audience"
4. realm = "ktor sample app"
5. }
JWT auth:
1. val jwtIssuer = environment.config.property("jwt.domain").getString()
2. val jwtAudience = environment.config.property("jwt.audience").getString()
3. val jwtRealm = environment.config.property("jwt.realm").getString()
5. install(Authentication) {
6. jwt {
7. realm = jwtRealm
8. verifier(makeJwtVerifier(jwtIssuer), jwtIssuer)
9. validate { credential ->
10. if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null
11. }
12. }
13. }
Using a JWK provider:
1. fun AuthenticationPipeline.jwtAuthentication(jwkProvider: JwkProvider, issuer: String, realm: String, validate: (JWTCredential) -> Principal?)
1. val jwkIssuer = "https://jwt-provider-domain/"
2. val jwkRealm = "ktor jwt auth test"
3. val jwkProvider = JwkProviderBuilder(jwkIssuer)
4. .cached(10, 24, TimeUnit.HOURS)
5. .rateLimited(10, 1, TimeUnit.MINUTES)
6. .build()
7. install(Authentication) {
8. jwt {
9. verifier(jwkProvider, jwkIssuer)
10. realm = jwkRealm
11. validate { credentials ->
12. if (credentials.payload.audience.contains(audience)) JWTPrincipal(credentials.payload) else null
13. }
14. }
15. }
