-
Notifications
You must be signed in to change notification settings - Fork 10
[DOCSW-379] feat: add doc for building plane app #119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
a7251fd
1fa1048
91892fb
31f11b4
a858faa
f3a7aad
85267b7
f694b53
a27648a
00c3ff5
777a6e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| --- | ||
| title: Build your Plane Integration app | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| sidebarTitle: Build your Plane Integration app | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| description: Step-by-step guide for developers to build and integrate an app with Plane.so using OAuth-based authentication and authorization workflow. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| --- | ||
|
|
||
| This guide provides step-by-step instructions for developers to build and integrate an app with Plane.so using an OAuth-based authentication and authorization workflow. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Introduction | ||
|
|
||
| Plane.so supports OAuth 2.0 for secure authentication and authorization of third-party applications. This ensures that apps can request and obtain access tokens on behalf of users, enabling seamless integration while maintaining security standards. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Prerequisites | ||
|
|
||
| * A Plane.so workspace. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| * Access to Plane.so developer portal. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| * Familiarity with OAuth 2.0 concepts (authorization code flow). | ||
| * A backend server to handle OAuth token exchange. | ||
|
|
||
| ## High-Level Workflow | ||
|
|
||
| 1. **Register your app on Plane.so developer portal** | ||
| 2. **Implement OAuth authorization code flow** | ||
| 3. **Obtain and store access tokens securely** | ||
| 4. **Make authenticated API requests to Plane.so** | ||
| 5. **Handle token refresh** | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Registering Your App | ||
|
|
||
| To build an OAuth application with Plane.so: | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| 1. Navigate to `https://app.plane.so/<workspace_slug>/settings/applications/`. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| 2. Click on the **Build your own** button. | ||
| 3. Fill out the form with the required details: | ||
|
|
||
| * **Redirect URIs**: Provide the URIs where Plane.so will send the authorization code. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| * **Contact Details**: Add your email or other contact information. | ||
| * **Webhook URL Endpoint**: Update this with your service's webhook endpoint. Plane.so will send webhooks for all changes that happen in the installed workspace. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| * **Organization Details**: Include contact email, privacy policy URL, terms of service URL, and any other relevant information. This helps Plane.so validate and approve your application for listing in the marketplace. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| 4. If you're building an agent (with or without using Plane's ADK) capable of performing operations when assigned or mentioned, enable the **Is Mentionable** checkbox during app creation. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We enabled Is Mentionable by default. This will result in all apps coming in assignees and other user fields. It'll be noise if there are too many apps in the assignees/members list. |
||
| 5. Once the app is created, securely store the **Client ID** and **Client Secret**. You will need these credentials to interact with Plane.so's API during the OAuth flow and for making authenticated API requests. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
|
Prashant-Surya marked this conversation as resolved.
|
||
| ## Authentication Setup | ||
|
|
||
| ### Generating Consent URL | ||
|
|
||
| Before handling types of authentication, if your app manages installation, you must generate the consent (authorization) URL to initiate the OAuth flow. Below is a sample implementation: | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| ```python | ||
| params = { | ||
| "client_id": os.getenv("PLANE_CLIENT_ID"), | ||
| "response_type": "code", | ||
| "redirect_uri": os.getenv("PLANE_REDIRECT_URI"), | ||
| # Optional: include state if needed | ||
| } | ||
|
|
||
| consent_url = f"https://api.plane.so/auth/o/authorize-app/?{urlencode(params)}" | ||
| ``` | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| There are two types of authenticated actions your application can perform: | ||
|
|
||
| 1. **User-authorized actions** — Actions performed on behalf of a user after they grant permission to your app via OAuth. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| 2. **App-authorized actions** — Actions that the app can perform independently within the workspace where it is installed (such as responding to webhooks or automation triggers). | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| We will describe how to configure and use each type in the following sections. | ||
|
|
||
| ### App-Authorized Actions (Client Credentials Flow) | ||
|
|
||
| When the user or admin installs the app, Plane.so will send an `app_installation_id` as part of the callback to the `redirect_uri` provided during consent URL generation. You can use this `app_installation_id` to request a bot token for your app. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| #### Example Pseudo-code | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| ```python | ||
| # Prepare basic auth header using client_id and client_secret | ||
| basic_auth = base64encode("client_id:client_secret") | ||
|
|
||
| # Prepare request data | ||
| payload = { | ||
| "grant_type": "client_credentials", | ||
| "app_installation_id": app_installation_id | ||
| } | ||
|
|
||
| # Make a POST request to fetch bot token | ||
| response = POST( | ||
| url="https://api.plane.so/auth/o/token/", | ||
| headers={"Authorization": f"Basic {basic_auth}", | ||
| "Content-Type": "application/x-www-form-urlencoded"}, | ||
| data=payload | ||
| ) | ||
|
|
||
| bot_token = response.data['access_token'] | ||
| expires_in = response.data["expires_in"] | ||
| ``` | ||
|
|
||
| ### User-Authorized Actions (Authorization Code Flow) | ||
|
|
||
| In this flow, your app exchanges the `code` received as a query parameter on the callback (to your `redirect_uri`) for an access token and refresh token. The access token is short-lived and must be refreshed using the refresh token when it expires. Both tokens should be securely stored. | ||
|
|
||
| #### Example Pseudo-code | ||
|
|
||
| ```python | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| # Exchange authorization code for access and refresh tokens | ||
| payload = { | ||
| "grant_type": "authorization_code", | ||
| "code": code, | ||
| "client_id": client_id, | ||
| "client_secret": client_secret, | ||
| "redirect_uri": redirect_uri | ||
| } | ||
|
|
||
| response = POST( | ||
| url="https://api.plane.so/auth/o/token/", | ||
| headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
| data=payload | ||
| ) | ||
|
|
||
| access_token = response.data["access_token"] | ||
| refresh_token = response.data["refresh_token"] | ||
| expires_in = response.data["expires_in"] | ||
|
|
||
| # When access token expires, use refresh token to get a new access token | ||
| refresh_payload = { | ||
| "grant_type": "refresh_token", | ||
| "refresh_token": refresh_token, | ||
| "client_id": client_id, | ||
| "client_secret": client_secret | ||
| } | ||
|
|
||
| refresh_response = POST( | ||
| url="https://api.plane.so/auth/o/token/", | ||
| headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
| data=refresh_payload | ||
| ) | ||
|
|
||
| access_token = refresh_response.data["access_token"] | ||
| ``` | ||
|
|
||
| ### Fetching App Installation Details | ||
|
|
||
| In both user-authorized and app-authorized flows, the `app_installation_id` identifies the app's installation within a specific workspace. It is recommended that developers fetch workspace details after OAuth is successfully completed. Plane.so provides an `app-installation` endpoint that works with both types of tokens. | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| #### Example Pseudo-code | ||
|
|
||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
| ```python | ||
| # Set authorization header with either access token or bot token | ||
| headers = { | ||
| "Authorization": f"Bearer {token}", | ||
| } | ||
|
|
||
| # Make GET request to fetch installation/workspace details | ||
| response = GET( | ||
| url=f"https://api.plane.so/auth/o/app-installation/?id={app_installation_id}", | ||
| headers=headers | ||
| ) | ||
|
|
||
| workspace_details = response.data[0] | ||
| ``` | ||
|
|
||
| #### Sample Response | ||
| ``` | ||
| [ | ||
| { | ||
| "id": "34b97361-8636-43dc-953e-90deedc8498f", | ||
| "workspace_detail": { | ||
| "name": "sandbox", | ||
| "slug": "sandbox", | ||
| "id": "7a2e5944-c117-4a7d-b5f4-058fe705d7d1", | ||
| "logo_url": null | ||
| }, | ||
| "created_at": "2025-05-16T13:50:27.865821Z", | ||
| "updated_at": "2025-06-23T08:57:26.976742Z", | ||
| "deleted_at": null, | ||
| "status": "installed", | ||
| "workspace": "7a2e5944-c117-4a7d-b5f4-058fe705d7d1", | ||
| "application": "ab235529-388a-4f51-a55a-78272251f5f1", | ||
| "installed_by": "63333ab1-c605-42fc-82f7-5cd86799eca1", | ||
| "app_bot": "7286aaa7-9250-4851-a520-29c904fd7654", // app's bot user id in the workspace | ||
| "webhook": "b1f4b7f1-51e8-4919-a84c-0b1143b51d2c" | ||
| } | ||
| ] | ||
| ``` | ||
|
|
||
| ## Using Plane SDKs | ||
|
|
||
| To simplify the OAuth flow and make it easier to build Plane apps, official SDKs are available: | ||
|
|
||
| * **Node.js**: `npm i @makeplane/plane-node-sdk` | ||
| * **Python**: `pip install plane-sdk` | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
|
|
||
| These SDKs provide helpers for OAuth and other common tasks, allowing developers to implement the above flows efficiently. | ||
|
|
||
| ## Listing Your App on Plane Marketplace | ||
|
|
||
| Apps built using the OAuth flow can be listed on the Plane Marketplace: [https://plane.so/marketplace/integrations](https://plane.so/marketplace/integrations) | ||
|
|
||
| To list your app, please contact the Plane team at [**support@plane.so**](mailto:support@plane.so). | ||
|
Prashant-Surya marked this conversation as resolved.
Outdated
|
||
Uh oh!
There was an error while loading. Please reload this page.