Create your own connector

To bootstrap the development, we provide an OpenAPI spec to automatically generate a server using Openapi Generator.

Bootstrap connector server

  1. Install the OpenAPI generator, on MacOS, with the following command:

    brew install openapi-generator
    

    Check Openapi Generator for other way of installing the generator app.

  2. Download the API spec file by clicking on this link.

  3. Check OpenAPI Generator documentation for available server generators.

  4. Proceed by generating the connector server stub. Check available configuration options for your chosen server generator to tweak the output of the generated code.

    openapi-generator generate \
      -g go-gin-server \
      -i openapi-connector-spec.yaml \
      -o opal-myconnector-connector
    

    Replace go-gin-server with the preferred server generator.

Filling in the blanks

Now that the boilerplate code has been generated, navigate into the generated code directory. Check the generated README.md file for instructions on how to run the code. You can change how you run and deploy the code based on your requirements and needs.

Check API Spec for details about each endpoint.

Nested Resources in connectors

Due to how hierarchical resources work in other system, the following assumptions are taken:

  • If a user has access to a parent resource, we infer access to all its child resources as well.
  • If a child resource is imported into Opal, all its parent resources will be imported as well.
  • We expect that the connector server correctly returns children resources when the “nested resources” option is enabled (see detailed example below).

In case the “Nested Resources” option is enabled in the connector setup, the following requirements are expected:

  • GET /resources: instead of listing ALL the available resources in the connector, only the resources without a parent (root resources) will need to be returned. Returning a resource that has a parent in this call might result in duplicate resources or errors.
  • GET /resources?parent_id=<id>: when passing the ID of a resource as a query param, only the immediate children of this resource need to be returned. If no children belong to this resource, an empty list should be returned instead.

Examples

Given this resource structure:

These are going to be the expected calls and responses to and from the connector:

  1. Query: GET /resources (Note: no ?parent_id= query param passed)
    1. Response: [resource_a, resource_b, resource_c]
  2. Query: GET /resources?parent_id=resource_a
    1. Response: [resource_aa]
  3. Query: GET /resources?parent_id=resource_aa
    1. Response: []
  4. Query: GET /resources?parent_id=resource_b
    1. Response: []
  5. Query: GET /resources?parent_id=resource_c
    1. Response: [resource_ca, resource_cb, resource_cd]
  6. Query: GET /resources?parent_id=resource_ca
    1. Response: []
  7. Query: GET /resources?parent_id=resource_cb
    1. Response: [resource_cba]
  8. Query: GET /resources?parent_id=resource_cd
    1. Response: []
  9. Query: GET /resources?parent_id=resource_cba
    1. Response: []

Example implementation

Over at GitHub we developed an example implementation of a custom connector against Datadog.

Example of request from Opal to the connector

Here's a snapshot of requests made from Opal to a generic connector implementation, it contains the raw path with query parameters, method, body and example of signatures. This can be used to unit test your connector implementation, if necessary.

URL|path|raw_query|method|headers|body|signing_secret|timestamp|signature
http://localhost:8080/resources?app_id=dsdd|/resources|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/1/users?app_id=dsdd|/resources/1/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/1/access_levels?app_id=dsdd|/resources/1/access_levels|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/2/users?app_id=dsdd|/resources/2/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/2/access_levels?app_id=dsdd|/resources/2/access_levels|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/3/users?app_id=dsdd|/resources/3/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/resources/3/access_levels?app_id=dsdd|/resources/3/access_levels|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups?app_id=dsdd|/groups|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/1/users?app_id=dsdd|/groups/1/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/1/resources?app_id=dsdd|/groups/1/resources|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/2/users?app_id=dsdd|/groups/2/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/2/resources?app_id=dsdd|/groups/2/resources|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/3/users?app_id=dsdd|/groups/3/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/3/resources?app_id=dsdd|/groups/3/resources|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/users?app_id=dsdd|/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835750"],"X-Opal-Signature":["896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835750|896277c63817aadbbdfea1f4fff18359b40e5ec5bd2b9dfc9aa449ee84c07ce4
http://localhost:8080/groups/1/resources/3?app_id=dsdd|/groups/1/resources/3|app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835866"],"X-Opal-Signature":["0c2044d2396e84917dc8050b1cb54cecaab5bc96ba814133eecf2adc9d6d4de8"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835866|0c2044d2396e84917dc8050b1cb54cecaab5bc96ba814133eecf2adc9d6d4de8
http://localhost:8080/groups/1/users/1?app_id=dsdd|/groups/1/users/1|app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835879"],"X-Opal-Signature":["244ae2057b438e7145df029bfd9a311f1be075b13d239b76c80f7223b90110d4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835879|244ae2057b438e7145df029bfd9a311f1be075b13d239b76c80f7223b90110d4
http://localhost:8080/groups/1/users/3?app_id=dsdd|/groups/1/users/3|app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835879"],"X-Opal-Signature":["244ae2057b438e7145df029bfd9a311f1be075b13d239b76c80f7223b90110d4"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835879|244ae2057b438e7145df029bfd9a311f1be075b13d239b76c80f7223b90110d4
http://localhost:8080/groups/1/users|/groups/1/users||POST|{"Accept":["application/json"],"Content-Type":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835889"],"X-Opal-Signature":["9a7fc343b92665839500263b0c6f14ff00bd33bdf1af37985525b2d51a12b7a1"]}|{"app_id":"dsdd","user_id":"5"}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835889|9a7fc343b92665839500263b0c6f14ff00bd33bdf1af37985525b2d51a12b7a1
http://localhost:8080/resources/3/users/3?access_level_id=2&app_id=dsdd|/resources/3/users/3|access_level_id=2&app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835901"],"X-Opal-Signature":["93030371458e338ba2f3b835854e3433bdef3ad4012659418977f58d42bc806f"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835901|93030371458e338ba2f3b835854e3433bdef3ad4012659418977f58d42bc806f
http://localhost:8080/resources/3/users/3?access_level_id=1&app_id=dsdd|/resources/3/users/3|access_level_id=1&app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835901"],"X-Opal-Signature":["93030371458e338ba2f3b835854e3433bdef3ad4012659418977f58d42bc806f"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835901|93030371458e338ba2f3b835854e3433bdef3ad4012659418977f58d42bc806f
http://localhost:8080/groups/1/resources/3?access_level_id=2&app_id=dsdd|/groups/1/resources/3|access_level_id=2&app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690835924"],"X-Opal-Signature":["04d5c6cad627f37263b957d8bce37c5fd743a480b927359f4af2171724d47970"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690835924|04d5c6cad627f37263b957d8bce37c5fd743a480b927359f4af2171724d47970
http://localhost:8080/groups/2?app_id=dsdd|/groups/2|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836017"],"X-Opal-Signature":["8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836017|8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6
http://localhost:8080/groups/2/users?app_id=dsdd|/groups/2/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836017"],"X-Opal-Signature":["8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836017|8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6
http://localhost:8080/groups/2/resources?app_id=dsdd|/groups/2/resources|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836017"],"X-Opal-Signature":["8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836017|8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6
http://localhost:8080/users?app_id=dsdd|/users|app_id=dsdd|GET|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836017"],"X-Opal-Signature":["8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836017|8d4b1c5bc918740859f51378fc4601642f653bb996a8debc1bf986b2cc632bf6
http://localhost:8080/groups/2/resources/2?app_id=dsdd|/groups/2/resources/2|app_id=dsdd|DELETE|{"Accept":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836024"],"X-Opal-Signature":["4581cba15df55453490bd42e26a73265dd442c87fcc9808bc9babef63268352a"]}|{}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836024|4581cba15df55453490bd42e26a73265dd442c87fcc9808bc9babef63268352a
http://localhost:8080/groups/2/resources|/groups/2/resources||POST|{"Accept":["application/json"],"Content-Type":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836045"],"X-Opal-Signature":["a18c00f9d430e65b340a86007572511c834d0d29717650c166ccfc65e1d78647"]}|{"access_level_id":"1","app_id":"dsdd","resource_id":"3"}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836045|a18c00f9d430e65b340a86007572511c834d0d29717650c166ccfc65e1d78647
http://localhost:8080/groups/2/users|/groups/2/users||POST|{"Accept":["application/json"],"Content-Type":["application/json"],"User-Agent":[""],"X-Opal-Request-Timestamp":["1690836053"],"X-Opal-Signature":["39add5b34eaaed4776f7172bf0ec036d7e2ab6eb3a564671f079a6bf28730046"]}|{"app_id":"dsdd","user_id":"5"}|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt|1690836053|39add5b34eaaed4776f7172bf0ec036d7e2ab6eb3a564671f079a6bf28730046

Testing a local connector implementation with Opal

If you're developing a connector and you want to test it out with your Opal instance before deploying it to a public server (or your own network), you can use a tool called ngrok to make a local server available with a public hostname. With a connector running locally on port :8080, run ngrok with:

ngrok http 8080

Now you can use the ngrok endpoint in your Connector app configuration in Opal.

Example of X-Opal-Signatures

In case you want to test X-Opal-Signature here's a replay of some requests made to a connector with method, signature, hash and encryption key, to build unit testing for your validation functions.

method|path|signature|timestamp|hash|encryption_key
GET|/resources/3|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/3/users|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/3/access_levels|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/2|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/2/users|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/2/access_levels|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/1|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/1/users|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/resources/1/access_levels|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
GET|/users|v0:1689194685:{}|1689194685|874d6f7810ae9611b816a1da9ed2ac6d38f6fef8b8b8770e5786727803146506|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
POST|/resources/1/users|v0:1689194631:{"app_id":"dsdd","user_id":"4"}|1689194631|2152942fccf3086d59de4cbbc708ee1861f87be76506560b755184d8ba90e8cc|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
POST|/resources/1/users|v0:1689194697:{"app_id":"dsdd","user_id":"4"}|1689194697|0f5dd435832cba2b26bcf98b775182deaacaf445334d403430969d42396a156d|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
POST|/resources/1/users|v0:1689194697:{"app_id":"dsdd","user_id":"5"}|1689194697|e4f572398bf72098a84f4f505a3a59b3429dcf64775df6032e3d348376ecc02a|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
DELETE|/resources/1/users/1|v0:1689194853:{}|1689194853|4700807ac9853cb813aaf6b6161f93634c6427bc4ea1625cd82fc42f3a8d2c5a|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt
DELETE|/resources/1/users/4|v0:1689194853:{}|1689194853|4700807ac9853cb813aaf6b6161f93634c6427bc4ea1625cd82fc42f3a8d2c5a|f3XX78hHLiqEQ0F5SjHkEt7RxYeNKmKt