JWT authentication using KituraKit

By David Jones

Created on 2019-08-12

With the release of KituraKit 0.0.24, it is now possible to make type-safe requests to a Kitura server using a JWT for authentication. In addition, we’d like to introduce Kitura-CredentialsJWT, which provides a convenient way to add JWT authentication to Codable routes.

In a previous blog post Swift JWT 3.0: Codable JSON web tokens, we outlined the code for implementing JWT authentication in Kitura for Codable routes. In this post, we’ll show how KituraKit makes it easy to perform type-safe requests to APIs requiring JWT authentication, and how Kitura-CredentialsJWT reduces the boilerplate required on the server side.

What is a JSON Web Token?

In short, a JWT is a small JSON payload consisting of a Header object, a Claims object and a signature. They are a self-contained way for securely transmitting information between parties. If you would like to know more about JWTs, check out jwt.io.


Setting up JWT authentication using KituraKit

Sending a JWT for authentication is simple: attach a JWTCredentials to your request, as in this example:

// Replace with a valid JWT string: three base64-encoded values separated by full stops.
let jwtString = "<my_jwt_token_string>"

client.get("/protected", credentials: JWTCredentials(token: jwtString)) { (user: User?, error: RequestError?) in
    guard let user = user else {
        return print("Failed to access protected resource")
    }
    print("User obtained: \(user)")
}

Under the covers, KituraKit will send your token in an Authorization: Bearer <token> header. When Kitura receives a request to the protected route, it will verify the token’s signature, and can then choose whether the JWT permits access to that resource based on its claims.

Server-side authentication using Kitura-CredentialsJWT

In a previous blog post Type-Safe Authentication using OAuth tokens, we introduced the TypeSafeCredentials protocol as part of Kitura-Credentials, and with it a number of initial implementations: TypeSafeGoogleToken, TypeSafeFacebookToken and TypeSafeHTTPBasic.

We’ve released 0.0.1 of Kitura-CredentialsJWT, which extends the JWT type to conform to TypeSafeMiddleware. This means that you can include it in your Codable route handler as follows:

import SwiftJWT
import CredentialsJWT

// Define the claims that must appear in the JWT
struct MyClaims: Claims {
    // Subject's id (e.g. name)
    let sub: String
}

// Set up TypeSafeJWT by specifying the method for verifying a JWT signature
let key = "<PrivateKey>".data(using: .utf8)!
TypeSafeJWT.verifier = .hs256(key: key)

// Use the JWT type as a Type-Safe Middleware to protect a route. The handler
// will only be invoked if the JWT can be successfully verified, and contains
// the required claims.
router.get("/protected") {  (jwt: JWT<MyClaims>, respondWith: (User?, RequestError?) -> Void) in
    // (Decide whether to permit the user access to this resource, based on the JWT claims)
    // Send the requested resource:
    let user = User(name: jwt.claims.sub)
    respondWith(user, nil)
}

Notice that, compared to the example in our previous post, there is no longer a requirement to implement the TypeSafeMiddleware protocol yourself. We just need to bootstrap the TypeSafeJWT configuration with a method (and key) for validating incoming JWTs.

The TypeSafeJWT type also provides a basic token cache facility, which can remember previously validated JWTs to reduce the computational overhead of verifying the same JWT repeatedly.


Using JWTs alongside other authentication methods

In addition, you can use JWT authentication as part of Kitura-Credentials’ TypeSafeMultiCredentials, which allows a single route handler to accept multiple types of authentication. For example:

import Credentials
import CredentialsJWT
import SwiftJWT

struct MyMultiAuthedUser: TypeSafeMultiCredentials {
    let id: String            // Protocol requirement
    let provider: String      // Protocol requirement
    let name: String          // Custom property

    // Acceptable methods of authentication: Google token, JWT and HTTP Basic
    static var authenticationMethods: [TypeSafeCredentials.Type] = [MyGoogleUser.self, MyBasicAuth.self, JWT<MyClaims>.self]

    init(successfulAuth: TypeSafeCredentials) {
        self.id = successfulAuth.id
        self.provider = successfulAuth.provider

        // Initialize additional properties based on authentication type.
        switch successfulAuth {
        case let googleToken as GoogleTokenProfile:
            self.name = googleToken.name
        case let jwt as JWT<MyClaims>:
            self.name = jwt.claims.sub
        default:  // HTTP Basic
            self.name = successfulAuth.id
        }
    }
}

The MyMultiAuthedUser type can then be used in place of JWT in your handler. (Note: the implementation of MyGoogleUser and MyBasicAuth is omitted here for brevity but more details can be found in the Multiple authentication methods section of Type-Safe Authentication using OAuth tokens.

For more details, you can check out the code at the IBM-Swift/Kitura-CredentialsJWT project on GitHub, and the API documentation on Kitura.io, and you are welcome to discuss the project by joining our Slack community. As always, feedback and contributions are welcomed!