Ktor - Setting up JWT
Tags: kotlin, jwt, ktor, recipe
Published: 2020-08-11 21:25:35

[JWT](https://jwt.io/) can be a tricky thing to implement yourself, fortunately you don't really have to do that, it's much easier, safer and faster to use one of many existing libraries. 

Most frameworks have such libraries, and so does [Ktor](https://ktor.io/servers/features/authentication/jwt.html). In this post I would like to save the knowledge on how to quickly setup basic JWT flow in your app. 

# 0. Add gradle import and install feature

``` groovy
implementation "io.ktor:ktor-auth-jwt:$ktor_version"
```

``` kotlin
 install(Authentication) { jwt { } }
```


# 1. Setup secret and config

Preferably you should use standard `application.conf` file to store configuration info. If so, just add your cypher's secret and other jwt related configs there (don't push it to control version system) 

``` config
jwt {
  "SECRET" = "123"
  "VALIDITY_MS" = "36000000" // 10 Hours
  "ISSUER" = "softwaret"
  "REALM" = "softwaret.kpdf"
}
``` 

# 2. Prepare token generation method

Pick user-related data that you want to store in token and then prepare token generation method (I use just login in my example) 

``` kotlin
fun generateToken(login: Login): String = JWT.create()
        .withSubject("Authentication")
        .withIssuer(issuer)
        .withClaim("login", login.value)
        .withExpiresAt(obtainExpirationDate())
        .sign(algorithm)

private fun obtainExpirationDate() = Date(System.currentTimeMillis() + tokenExpirationPeriodMs) # expiration period from config file
``` 

# 3. Pass token to user after login

Return the new token in any way you like and let client set it as its `Authorization` header with value `Bearer $token` (eg `Authorization: Bearer 123`).

# 4. Setup token validation 

Add body to installed JWT application's feature

``` kotlin 
 jwt {
            realm = "jwt.REALM" #realm from config file
            verifier(buildJwtVerifier())
            validate { jwtCredential -> validateCredential(jwtCredential) }

        }
}
```

**Verifier** should check whether token is correct and can be trusted, fortunately the framework takes care of this for us, just create a function which build the verifier: 

``` kotlin
fun buildJwtVerifier() = 
    JWT.require(Algorithm.HMAC512("jwt.SECRET")) # secret from config file 
        .withIssuer(issuer) # issuer from config file 
        .build()
```

**Validator** should check whether any user (or any other entity in your app) matches the passed data (login in my example) and sets it as the call's principle. This principle with be later available for any call handling method which requires authentication, so that one can easily check wich user asked about data. 

``` kotlin 
fun validateCredential(jwtCredential: JWTCredential) =
    if (userByLoginExists(jwtCredential.payload.getClaim("login")) {
        JWTPrincipal(jwtCredential.payload)
    } else {
        null
    }
``` 

# 5. Put any route which requires authentication inside `authenticate` block

Just wrap any route in `authenticate` lambda and it will easily handle JWT authentication and return 401 if token is invalid. 

``` kotlin
authenticate {
            get("/authentication") {
                call.respond(message = "Authentication is valid!")
            }
        }
```

And that's it! Happy JWT-ing in the future!

*Real life code example of JWT implementation can by found here: [github.com/Softwaret/kpdf](github.com/Softwaret/kpdf)*