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