Required dependencies: io.ktor:ktor-server-auth
, io.ktor:ktor-server-auth-jwt
Code examples: auth-jwt-hs256, auth-jwt-rs256
JSON Web Token is an open standard that defines a way for securely transmitting information between parties as a JSON object. This information can be verified and trusted since it is signed using a shared secret (with the HS256
algorithm) or a public/private key pair (for example, RS256
).
Ktor handles JWTs passed in the Authorization
header using the Bearer
schema and allows you to:
- verify the signature of a JSON web token;
- perform additional validations on the JWT payload.
You can get general information about authentication and authorization in Ktor in the section.
To enable JWT
authentication, you need to include the ktor-server-auth
and ktor-server-auth-jwt
artifacts in the build script:
implementation("io.ktor:ktor-server-auth:$ktor_version")
implementation("io.ktor:ktor-server-auth-jwt:$ktor_version")
implementation "io.ktor:ktor-server-auth:$ktor_version"
implementation "io.ktor:ktor-server-auth-jwt:$ktor_version"
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-server-auth</artifactId>
<version>${ktor_version}</version>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-server-auth-jwt</artifactId>
<version>${ktor_version}</version>
</dependency>
The JWT authorization flow in Ktor might look as follows:
- A client makes a
POST
request with the credentials to a specific authentication route in a server application. The example below shows an HTTP clientPOST
request with the credentials passed in JSON:{src="snippets/auth-jwt-hs256/requests.http" lines="2-8"} - If the credentials are valid, a server generates a JSON web token and signs it with the specified algorithm. For example, this might be
HS256
with a specific shared secret orRS256
with a public/private key pair. - A server sends a generated JWT to a client.
- A client can now make a request to a protected resource with a JSON web token passed in the
Authorization
header using theBearer
schema.{src="snippets/auth-jwt-hs256/requests.http" lines="13-14"} - A server receives a request and performs the following validations:
- Verifies a token's signature. Note that a verification way depends on the algorithm used to sign a token.
- Perform additional validations on the JWT payload.
- After validation, a server responds with the contents of a protected resource.
To install the jwt
authentication provider, call the jwt function inside the install
block:
install(Authentication) {
jwt {
// Configure jwt authentication
}
}
You can optionally specify a provider name that can be used to authenticate a specified route.
In this section, we'll see how to use JSON web tokens in a server Ktor application. We'll demonstrate two approaches to signing tokens since they require slightly different ways to verify tokens:
- Using
HS256
with a specified shared secret. - Using
RS256
with a public/private key pair.
You can find full runnable projects here: auth-jwt-hs256, auth-jwt-rs256.
To configure JWT-related settings, you can create a custom jwt
group in the application.conf configuration file. This file might look as follows:
{style="block" src="snippets/auth-jwt-hs256/src/main/resources/application.conf" lines="11-16"}
{style="block" src="snippets/auth-jwt-rs256/src/main/resources/application.conf" lines="11-16"}
Note that secret information should not be stored in the configuration file as plain text. Consider using environment variables to specify such parameters.
{type="warning"}
You can access these settings in code in the following way:
{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="24-27"}
{style="block" src="snippets/auth-jwt-rs256/src/main/kotlin/com/example/Application.kt" lines="31-34"}
To generate a JSON web token, you can use JWTCreator.Builder. Code snippets below show how to do this for both HS256
and RS256
algorithms:
{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="50-61"}
{style="block" src="snippets/auth-jwt-rs256/src/main/kotlin/com/example/Application.kt" lines="58-72"}
post("/login")
defines an authentication route for receivingPOST
requests.call.receive<User>()
receives user credentials sent as a JSON object and converts it to aUser
class object.JWT.create()
generates a token with the specified JWT settings, adds a custom claim with a received username, and signs a token with the specified algorithm:- For
HS256
, a shared secret is used to sign a token. - For
RS256
, a public/private key pair is used.
- For
call.respond
sends a token to a client as a JSON object.
The realm
property allows you to set the realm to be passed in WWW-Authenticate
header when accessing a protected route.
{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="27-30,46-47"}
The verifier
function allows you to verify a token format and its signature:
- For
HS256
, you need to pass a JWTVerifier instance to verify a token. - For
RS256
, you need to pass JwkProvider, which specifies a JWKS endpoint for accessing a public key used to verify a token. In our case, an issuer ishttp://0.0.0.0:8080
, so a JWKS endpoint address will behttp://0.0.0.0:8080/.well-known/jwks.json
.
{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="24-35,46-47"}
{style="block" src="snippets/auth-jwt-rs256/src/main/kotlin/com/example/Application.kt" lines="32-44,55-56"}
-
The
validate
function allows you to perform additional validations on the JWT payload. Check thecredential
parameter, which represents a JWTCredential object and contains the JWT payload. In the example below, the value of a customusername
claim is checked.{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="28-29,36-42,46-47"}
In a case of successful authentication, return JWTPrincipal.
-
The
challenge
function allows you to configure a response to be sent if authentication fails.{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="28-29,43-47"}
After configuring the jwt
provider, you can define the authorization for the different resources in our application using the authenticate
function. In a case of successful authentication, you can retrieve an authenticated JWTPrincipal inside a route handler using the call.principal
function and get the JWT payload. In the example below, the value of a custom username
claim and a token expiration time are retrieved.
{style="block" src="snippets/auth-jwt-hs256/src/main/kotlin/com/example/Application.kt" lines="49,63-71"}