JetBrains Space Help

Verify Requests

For the sake of security, all requests coming from Space must be checked for authenticity. Space SDK lets you implement both methods of verifying Space requests: via a verification token and via a signing key.

Verifying requests using a verification token

The idea behind the method is to compare the verification token in the request body with the request your application obtained during registration in Space. As the verification token is a part of the payload, the SDK provides an extension method for the ApplicationPayload class:

ApplicationPayload.verifyWithToken(verificationToken: String): Boolean
The method returns true if verificationToken is equal to the token in the payload.

This is how a simple implementation of this method can look like:

// token issued during app registration val verificationToken = "abc123" fun verifyPayload(payload: ApplicationPayload): Boolean { return payload.verifyWithToken(verificationToken) } fun Routing.backToSpace() { // the endpoint that handles Space requests post("api/back-to-space") { // get payload as text val body = call.receiveText() // deserialize payload into ApplicationPayload val payload = readPayload(body).also { if (!verifyPayload(it)) { call.respond(HttpStatusCode.Unauthorized) return@post } } // ... } }

Verifying requests using a signing key

We recommend using verification with a signing key instead of the verification token method as it is more secure.

The idea of this method is that Space uses a special signing key to calculate hash for every request it sends to your application. The application should calculate the hash as well and compare it to the hash in the request.

There are no helper functions in Space SDK for this method, so, our task is to implement the verification logic described in Verify Requests from Space. To calculate hash, you can use the Apache Commons Codec library. To reference it from a Gradle project, add the following lines to build.gradle:

  • To repositories:

    repositories { jcenter() // ... other repos }

  • To dependencies:

    dependencies { compile group: 'commons-codec', name: 'commons-codec', version: '1.15' // ... other dependencies }

This is how a simple implementation of this method can look like:

import org.apache.commons.codec.digest.HmacAlgorithms import org.apache.commons.codec.digest.HmacUtils // ... other imports // signing key issued during app registration val signingKey = "abc123" // calculate hash and compare it to hash from request fun verifyPayloadWithSigningKey(body: String, signature: String, timestamp: String) : Boolean { val checkedSignature = HmacUtils(HmacAlgorithms.HMAC_SHA_256, signingKey). hmacHex("$timestamp:$body") return signature == checkedSignature } fun Routing.backToSpace() { // the endpoint that handles Space requests post("api/back-to-space") { // get payload as text val body = call.receiveText() // get timestamp and message hash calculated by Space val signature = call.request.header("X-Space-Signature") val timestamp = call.request.header("X-Space-Timestamp") // check hash val verified = signature != null && timestamp != null && !verifyPayloadWithSigningKey(body, signature, timestamp) if (!verified) { call.respond(HttpStatusCode.Unauthorized) return@post } // ... } }
Last modified: 14 December 2020