JSON Web Tokens
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.
Add dependencies
To enable JWTauthentication, you need to include the ktor-auth and ktor-auth-jwt artifacts in the build script:
JWT authorization flow
The JWT authorization flow in Ktor might look as follows:
A client makes a
POSTrequest with the credentials to a specific authentication route in a server application. The example below shows an HTTP clientPOSTrequest with the credentials passed in JSON:POST http://localhost:8080/login Content-Type: application/json { "username": "jetbrains", "password": "foobar" }If the credentials are valid, a server generates a JSON web token and signs it with the specified algorithm. For example, this might be
HS256with a specific shared secret orRS256with 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
Authorizationheader using theBearerschema.GET http://localhost:8080/hello Authorization: Bearer {{auth_token}}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.
Install JWT
To install the jwt authentication provider, call the jwt function inside the install block:
You can optionally specify a provider name that can be used to authenticate a specified route.
Configure JWT
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
HS256with a specified shared secret.Using
RS256with a public/private key pair.
You can find full runnable projects here: auth-jwt-hs256, auth-jwt-rs256.
Step 1: Configure JWT settings
To configure JWT-related settings, you can create a custom jwt group in the application.conf configuration file. This file might look as follows:
You can access these settings in code in the following way:
Step 2: Generate a token
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:
post("/login")defines an authentication route for receivingPOSTrequests.call.receive<User>()receives user credentials sent as a JSON object and converts it to aUserclass 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.
call.respondsends a token to a client as a JSON object.
Step 3: Configure realm
The realm property allows you to set the realm to be passed in WWW-Authenticate header when accessing a protected route.
Step 4: Configure a token verifier
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.
Step 5: Validate JWT payload
The validate function allows you to perform additional validations on the JWT payload in the following way:
Check the
credentialparameter, which represents a JWTCredential object and contains the JWT payload. In the example below, the value of a customusernameclaim is checked.In a case of successful authentication, return JWTPrincipal. If authentication fails, return
null.
Step 6: Define authorization scope
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.