JetBrains Space Help

Distribute Multi-Org Applications

A multi-org application is an application that can be installed to multiple Space organizations. Organization users can install the application either by clicking a direct link or by using JetBrains Marketplace. In order the application could be used by multiple organizations, it must be able to configure itself in a particular organization via Space API calls. Learn more about application configuration.

Specifics of multi-org applications

  • Authorization via the Client Credentials flow is always enabled for all multi-org applications.

  • Verification with a public key is always enabled for all multi-org applications.

  • After a user installs a multi-org application, Space sends initialization payload InitPayload to the application endpoint.

  • Only the application itself is allowed to change its parameters (authorization flow, authentication, webhooks, and so on). Space users (including administrators) can neither change the parameters nor view the payload sent to the application. This is done to prevent Space users from getting unauthorized access to the application data or impersonating the application.

Prepare the application for distribution

Single-org applications require manual configuration: On the application page in Space, users must specify required extension features, application permissions, webhooks, and other settings. On the contrary, multi-org applications must be able to perform such configuration by themselves. The main configuration steps are described below.

1. Handle InitPayload

During the application installation, after a user clicks the Install button, Space sends a payload of the InitPayload type to the application endpoint. This is how the payload may look like:

{ "className": "InitPayload", // Client secret issued to the app "clientSecret": "2e14111c13daa385590ded764c0ec8d3fd20ae02ce96d0c7e1728e7", // URL of Space instance where the app is installed "serverUrl": "https://mycompany.jetbrains.space", // A string value that Space sends back to the application // Can be used to track installation state "state": "", // Client ID issued to the app "clientId": "81ec3fba-95ca-4995-9b44-218e743", // ID of the user who installed the app to the orgranization "userId": "2BgVYn24Jx6u" }

Your task as an application developer is to handle the InitPayload in the application. On receiving the payload, the application should configure its basic parameters: specify the required extensions, permissions, and other settings.

With the Kotlin Space SDK, you can use the Space helper object to handle the payload. For example, in a Ktor application:

// we use in-memory storage for storing Space instances // in a real app, use a persistent storage, e.g., a database val spaceInstances = HashMap<String, SpaceAppInstance>() object AppInstanceStorage : SpaceAppInstanceStorage { override suspend fun loadAppInstance(clientId: String): SpaceAppInstance? { return spaceInstances[clientId] } override suspend fun saveAppInstance(appInstance: SpaceAppInstance) { spaceInstances[appInstance.clientId] = appInstance } } val ktorClient = ktorClientForSpace() class KtorRequestAdapter(private val call: ApplicationCall) : RequestAdapter { override suspend fun receiveText() = call.receiveText() override fun getHeader(headerName: String) = call.request.headers[headerName] override suspend fun respond(httpStatusCode: Int, body: String) { call.respond(HttpStatusCode.fromValue(httpStatusCode), body) } } fun Routing.routes() { post("api/myapp") { Space.processPayload( KtorRequestAdapter(call), ktorClient, AppInstanceStorage ) { payload -> when (payload) { is InitPayload -> { // Handle the payload: // 1. Specify required UI extensions // 2. Request permissions // 3. Other activities // If initialization is successful, // respond with HTTP 200 OK SpaceHttpResponse.RespondWithOk } else -> { SpaceHttpResponse.RespondWithOk } } } } }

2. Specify required UI extensions

The application must explicitly ask Space to enable particular extension features. For example, if your application is a chatbot, it requires the Chatbot feature. If it adds a menu item to, say, an issue menu item, it requires the Issue menu item feature, and so on.

To enable a feature, the application must use the Space API. For example:

space.applications.setUiExtensions( contextIdentifier = ProjectPermissionContextIdentifier(ProjectIdentifier.Id("2WnWIP2gPOyz")), extensions = listOf(IssueMenuItemUiExtensionIn( displayName = "Custom item", description = null, menuItemUniqueCode = "abc1234", visibilityFilters = emptyList() )) )
PATCH https://jetbrains.team/api/http/applications/ui-extensions Authorization: Bearer here-goes-auth-token Accept: application/json Content-Type: application/json { "contextIdentifier": "project:id:2WnWIP2gPOyz", "extensions": [ { "className": "IssueMenuItemUiExtensionIn", "displayName": "Custom item", "menuItemUniqueCode": "abc1234", "visibilityFilters": [] } ] }

3. Request permissions

Before making calls to particular Space endpoints, the application must obtain the corresponding permissions. The exact implementation of this process depends on the selected authorization flow. Learn more

4. Other activities

The initialization phase might include any additional activity like registering webhooks, getting data from Space, creating necessary Space entities, etc. Note that you can update application settings by making a call to the Space API. For example, to change the application name:

space.applications.updateApplication( application = ApplicationIdentifier.ClientId("here-goes-app-client-id"), name = "new-app-name" )
PATCH https://jetbrains.team/api/http/applications/clientId:here-goes-app-client-id Authorization: Bearer here-goes-auth-token Accept: application/json Content-Type: application/json { "name": "new-app-name" }

5. Handle AppPublicationCheckPayload (only for JetBrains Marketplace apps)

After you submit the application to JetBrains Marketplace, it will go through the verification process. This includes passing a basic health check – JetBrains Marketplace sends a AppPublicationCheckPayload to the application's endpoint. The application must respond with the 200 OK HTTP status code.

If your application uses the Space.processPayload() helper method as shown here, you don't have to implement the handling by yourself. The AppPublicationCheckPayload will be processed automatically. In all other cases, you must add the code that handles the payload, for example:

//... post("api/space") { val body = call.receiveText() // ... when (val payload = readPayload(body)) { // ... is AppPublicationCheckPayload -> { call.respond(HttpStatusCode.OK) } } }

Distribute the application via JetBrains Marketplace

The main benefit of distributing your application via JetBrains Marketplace is that in this case, any company that uses Space can find and install it through their Extensions | Applications page. A typical distribution flow looks as follows:

  • You add your application to JetBrains Marketplace.

  • A Space user installs the application through the Extensions | Applications page or by clicking an installation link generated by JetBrains Marketplace.

    Install from Marketplace
  • The user is redirected to the application installation dialog.

  • The user clicks Install in the dialog.

  • At this point, Space sends InitPayload to the application endpoint.

  • The application performs initialization and responds with the 200 OK HTTP status code.

  • The application appears on the Extensions | Installed to organization page in the Space organization.

To add the application to JetBrains Marketplace

  1. Register at https://plugins.jetbrains.com/

  2. Click on your profile in the top right corner and choose Upload plugin. This will open the upload page.

  3. In the list of products on the left, change IDEs to Space.

  4. Specify application settings:

    • Name, ID, and Description stand for the application name, a unique identifier, and a short application description.

    • Endpoint is an HTTPS URL of the application endpoint. Space will use it to send messages to the application.

    • Icon, Vendor, and License stand for an application icon (in SVG format), a developer company, and a license that is used to distribute the application.

    • In Authentication flows, choose Authorization Code Flow if you want to enable it for your application. In case, you enable it, specify the flow options: redirect URIs and the PKCE requirement. Learn more

      Note that the Client Credentials flow is always enabled for multi-org applications.

  5. Click Add Application.

  6. Now, your application must be verified by JetBrains. Note that verification includes a basic health check. You can initiate the check by clicking the Send for verification button. Otherwise, it'll be initiated by the Marketplace administrator. Learn more about the verification process here.

  7. After the application is verified, it will appear on the Administration | Applications | Marketplace page of all Space organizations.

As an alternative to JetBrains Marketplace, you can distribute your application with a direct link. All you need is to generate a link and provide it to Space users.

A typical distribution flow looks as follows:

  • You create a distribution link for your application.

  • A Space user clicks the link in a browser and selects their Space organization.

  • The user is redirected to the application connection dialog in their Space organization.

    App connect dialog
  • The user clicks Connect in the dialog.

  • At this point, Space sends InitPayload to the application endpoint.

  • The application must perform initialization and respond with the 200 OK HTTP status code.

  • After this, the application will appear on the Extensions | Installed to organization page in the Space organization.

Space applications support three link types:

  • A link for an application available in JetBrains Marketplace:

    https://jetbrains.com/space/app/install-app?marketplace-app=<marketplace-application-id>&name=<url-encoded-app-name>
  • A generic link:

    https://jetbrains.com/space/app/install-app?<app-params>
  • A link personalized for a particular organization:

    https://somecompany.jetbrains.space/extensions/installedApplications/new?<app-params>

    The link above will work only for the somecompany organization.

With the help of URL parameters (<app-params>), you can configure application settings. See the details below.

General settings:

  • name: (Required) The default application name. Space organization users can change this name after installation.

  • endpoint: An HTTPS URL of the application endpoint (url-encoded). Space will use it to send messages to the application.

  • pair: By default true. If pair=true, Space will send initialization payload InitPayload to the application after the application is added to the organization. If you don't handle InitPayload in your application, set pair=false.

  • state: A string value that Space sends to the application in initialization payload InitPayload. Use it to track the installation process across different systems while a user is redirected in the browser.

Authorization settings (note that the Client Credentials flow is always enabled):

  • code-flow-enabled: Set code-flow-enabled=true to enable Authorization Code flow for the application.

  • code-flow-redirect-uris: (Required if code-flow-enabled=true) Redirect URIs for the Authorization Code flow.

  • pkce-required: Set pkce-required=true to enable PKCE validation for the Authorization Code flow.

Verification of Space requests (note that verification with a public key is recommended and always enabled):

For example, a generic link might look as follows:

https://jetbrains.com/space/app/install-app?name=Homepage%20demo&endpoint=https%3A%2F%2Fspace-app-homepage-example.eu-west-1.eks.intellij.net%2Fapi%2Fspace&code-flow-enabled=true&code-flow-redirect-uris=https%3A%2F%2Fnowhere.domain

Last modified: 06 December 2022