JetBrains Space internal Help

Verify Requests from Space

If your application is supposed to receive requests from Space (for example, a chatbot that listens to requests on some endpoint), it should be able to verify whether the incoming requests are authentic. Space provides a number of verification methods you can choose from when registering your application.

This topic provides general instructions on how to verify Space requests using:

For the instructions on how to verify requests with the help of Space SDK, refer to this topic.

(Recommended) Verifying requests using a public key

We recommend using this verification method as the most secure.

This verification method is based on asymmetric encryption. The typical workflow looks as follows:

  1. Before sending a request to your application, Space calculates a request hash.

  2. Space generates a request signature: It takes the calculated hash and encrypts it with a private key. The signature is sent along with the request in the X-Space-Public-Key-Signature HTTP header. For example, this is a sample Space request including headers:

    POST /api/myapp HTTP/1.1 X-Forwarded-For : ::ffff:123.123.123.123 X-Forwarded-Proto : https X-PageKite-Port : 443 X-Space-Timestamp : 1632844347462 X-Space-Public-Key-Signature : iOjFEi5EpW+FbU1CJl+oc0QOJbIrv7kaV/VTEMa5i0ot6418N3ObQGz2C0tB8e2N4vHKQ7LWMZZ+OJexeHHoJGvL0XN7nwWb5k7Hn1DOPMMkWgSi6kL5orkyOHqIDPaHgZzX6IGbl3LP/aPms7E1NXaFRIfxuUQGdsDeA7yCjTIv/Rq8AbV9VqVI5TudAhHmaxh6R19wgtzWxaud27rsXV8INAvwXAQLMf5Ld+E1Mzi67qrS79Jxa7U34SJjC9xDe1wYMCZGc+G+6L4zdqVB08C2MCfI1IVYzqiHLyJgCHxhBmvjJ8JivoqadbRKOrbKShvSzHqFD5geEBovO0HqKA== User-Agent : Space (81383) Ktor http-client Accept-Charset : UTF-8 Accept : */* Content-Length : 196 Content-Type : application/json Host: 12345abcdef.ngrok.io Connection : Keep-Alive {"className":"ListCommandsPayload","clientId":"f6df3d26-d9fc-41c5-9fbd-0e7896f2cfb0","userId":"2BgVYn24Jx6u"}

  3. The application receives the request. Now, it should verify the request signature.

    First, the application must obtain a public key from Space. To do this, the application must send an HTTP request to the applications/public-keys Space endpoint. For instance, this is how a request may look like:

    GET https://mycompany.jetbrains.space/api/http/applications/clientId:abc1234/public-keys Authorization: Bearer abc1234 Accept: application/json

    Here clientId is the client ID assigned to your application during registration. API Playground can help you with generating a request:

    Public keys HTTP API
  4. In the reply, Space sends a JSON Web Key set. Typically, the set contains only one key. When a current public key becomes outdated, there is a period of time when the set contains two keys (the current one and a new one).

    For each key in the set, the application must:

    • Get the value of the X-Space-Timestamp header and the request body.

    • Generate a string consisting of the timestamp and the body. Use colon : as a delimiter. For example in Kotlin, it can look like follows:

      val str = "$timestamp:$body"
      In case of the sample request above, the str value would be:
      1632844347462:{"className":"ListCommandsPayload", "clientId":"f6df3d26-d9fc-41c5-9fbd-0e7896f2cfb0","userId":"2BgVYn24Jx6u"}

    • Calculate string hash using SHA512.

    • Decrypt the content of the X-Space-Public-Key-Signature header using the RSA algorithm.

    • Compare the decrypted signature with the calculated hash. If they are equal, the application is allowed to process the request, if not, the application must return the HTTP 401 Unauthorized response code.

      Note that only one key from the set must return the correct hash result.

Important: After a certain period of time, public keys become outdated. So, while the application can cache public keys (to avoid requesting them from Space each time), the cache should be cleared once the cached keys don't produce a correct signature. Space SDK does such caching under the hood.

Verifying requests using a signing key

The idea of this method is that Space uses a special signing key to generate a hash for every request it sends to your application. The calculated hash is sent in the X-Space-Signature HTTP header. In turn, your application has to use the same signing key to calculate a hash of a received request. Then it should compare the calculated hash value with the hash value in the request.

The typical verification workflow looks as follows:

  1. During registration of your application, Space can issue it a signing key. To get the key, you should open the Endpoint tab of the application settings and click Generate under Signing key.

  2. Save the signing key in your application, for example, as a string constant.

  3. Before Space sends a request to your application, it calculates the request hash using the generated signing key and puts it into the X-Space-Signature header. For example, this is a sample Space request including headers:

    POST /api/myapp HTTP/1.1 Host: 12345abcdef.ngrok.io User-Agent: Space (61355) Ktor http-client Content-Length: 163 Accept: */* Accept-Charset: UTF-8 Content-Type: application/json X-Forwarded-For: 123.456.123.456 X-Forwarded-Proto: https X-Space-Signature: 2aa8cba6217a28686de0ca8dcfe2a1d0795e343d744a0c5307308e43777593a5 X-Space-Timestamp: 1607623492912 Accept-Encoding: gzip {"className":"ListCommandsPayload","accessToken":"","verificationToken":"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3","userId":"2kawvQ4F6GM6"}
  4. Now, it's the application's turn to calculate the request hash. To do this:

    • Get the value of the X-Space-Timestamp header and the request body.

    • Generate a string consisting of the timestamp and the body. Use colon : as a delimiter. For example in Kotlin, it can look like follows:

      val str = "$timestamp:$body"
      In case of the sample request above, the str value would be:
      1607623492912:{"className":"ListCommandsPayload","accessToken":"","verificationToken":"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3","userId":"2kawvQ4F6GM6"}

    • Use HMAC SHA256 to hash the string.

  5. Compare the calculated hash with the one you get from the X-Space-Signature header. If they are equal, the application is allowed to process the request, if not, the application must return the HTTP 401 Unauthorized response code.

(Obsolete) Verifying requests using a verification token

The typical verification workflow looks as follows:

  1. During registration of your application, Space can issue it a verification token. To get the token, you should open the Endpoint tab of the application settings and click Generate under Verification token.

  2. Save this token in your application, for example, as a string constant.

  3. When Space sends a request to your application, it puts this verification token in the request body. For example, this is how the body of a slash command request looks like (a user presses / in the chatbot's channel):

    { "className": "ListCommandsPayload", "accessToken": "", "verificationToken": "d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3", "userId": "2kawvQ4F6GM6" }

  4. The task of the application is to get the verificationToken from the request payload and compare it to the token stored in the application. If they are equal, the application is allowed to process the request, if not, the application must return the HTTP 401 Unauthorized response code.

Verifying requests using an SSL client key

This verification method implies that all requests from Space to the application are encrypted with an SSL client key. The verification is handled not by the application but by the web server that hosts the application. Generally, to configure this verification method, you should:

  1. Generate an SSL keystore file with private and public keys.

  2. Upload the SSL keystore file to Space.

  3. During application registration, choose the uploaded keystore.

  4. On the web server that hosts your application, configure SSL client certificate authentication. For the exact instructions, refer to the web server official documentation.

Verifying requests using HTTP authentication

This method implies using the standard HTTP authentication based on the Authorization request header. There are two ways to perform verification: using a bearer token and using basic authentication by providing a username and a password.

Bearer token

  1. During registration of your application, select HTTP Authentication and then Bearer.

  2. In Token, specify a verification token.

  3. When sending a request, Space will add this token to the Authorization header. For example:

    POST /api/myapp HTTP/1.1 Host: 12345abcdef.ngrok.io User-Agent: Space (61355) Ktor http-client X-Space-Timestamp: 1624376380652 Authorization: Bearer abc1234 X-Space-DeliveryID: e90ffc27-87dc-43f3-a13a-ac3860d53770 Accept-Charset: UTF-8 Accept: /

  4. The task of the application is to get the Authorization: Bearer header value and compare it to the token stored in the application. If they are equal, the application is allowed to process the request, if not, the application must return the HTTP 401 Unauthorized response code.

Basic authentication

  1. During registration of your application, select HTTP Authentication and then Basic.

  2. Specify a Username and a Password.

  3. Space will use the specified credentials to create a single string: username:password (a colon : is used as a separator). Then it will encode the string using the Base64 encoding.

    When sending a request, Space will add the generated string to the Authorization header. For example, for johndoe:pwd1234:

    POST /api/myapp HTTP/1.1 Host: 12345abcdef.ngrok.io User-Agent: Space (61355) Ktor http-client X-Space-Timestamp: 1624449426984 Authorization: Basic am9obmRvZTpwd2QxMjM0 X-Space-DeliveryID: 2cd74c76-9cbb-4da5-81ab-7ce578145ccc Accept-Charset: UTF-8 Accept: /

  4. The task of the application is to get the Authorization: Basic header value, decode it back to string and compare it to the credentials stored in the application. If they are equal, the application is allowed to process the request, if not, the application must return the HTTP 401 Unauthorized response code.

Last modified: 19 October 2021