How to integrate with Productboard via OAuth2 - developer documentation

Important: This document is meant to describe how to enable OAuth2 authorization with Productboard. It isn’t supposed to serve as general learning resource for OAuth2 protocol. To learn more about OAuth2 itself, please consult another resources, such as oauth.com
Note: Looking for registering an OAuth2 application with us? Read the Registering an OAuth2 application section. Got questions? Reach out to us at oauth2@productboard.com.

Let’s imagine you are working on a product called AwesomeSheet, building next-gen online spreadsheets. You created a script, which makes use of Productboard’s public API to export features data from Productboard to your application. Now you want to enable your users to import their data from Productboard to AwesomeSheet by simply clicking a button. The problem is - how will the script get access to the Productboard data of your user?

One possibility would be to navigate the user to generate a Public API Access Token in the Productboard application and hand it over to you. This approach has several downsides:

  • It’s a multi-step manual process prone to human error and possibly confusing to less technical users
  • The access token is valid forever (unless explicitly revoked by the user). If malicious 3rd party would get hold of it, they could use it for long-term spying on your user’s data
  • The access token would give the script unrestricted access to the whole Productboard API on behalf of the user. So the user would have to blindly trust that the script will use it only for its declared purpose (exporting features) and not let’s say for reading valuable insights from your user’s customers or deleting their data.

To address these issues we are providing you with the ability to allow your users to grant access to their Productboard workspaces to an external application in a safe, human-friendly, transparent, and restricted manner. We achieve this using OAuth2, which is an industry-standard protocol for authorization.

In the rest of this document, we will walk you through the process of enabling this kind of integration, starting with registering your application and ending with automated generation of access and refresh tokens.

Note: only Makers with admin access are able to authorize OAuth2 applications to access their workspaces.

In this article:

OAuth2 authorization flow

Registering an OAuth2 application

You can register and manage your OAuth2 application at https://app.productboard.com/oauth2/applications. You need an active Productboard user account to access this page.

Getting the authorization code

Once you have the application registered you can trigger the authorization flow for the user. You do this by crafting a special URL your user will visit after clicking on a link/button you present to them. The URL base path will be app.productboard.com/oauth2/authorize and it will contain the following query parameters:

Parameter Description Example value Required
client_id Unique identifier of the application (received after registration) - random string hqAGVdAy9FZX5Ky5cBHUB2FshBdSO6eN75tWMX46ZZd Yes
response_type The value is always code to indicate the client expects authorization code in the response. code Yes
redirect_uri One of the registered redirect URIs (but URL-encoded). Must be an exact match. https%3A%2F%2Fawesomesheet.com%2Foauth2-callback%3Ffoo%3Dbar Yes
state An arbitrary string that will be sent back unchanged in the response. Useful as CSRF prevention and for encoding state (e.g. to redirect users back where they were before starting the authorization process) 4agg4zF76rwd3bBM No
code_challenge Base64-URL-encodedSHA256 hash of code_verifier generated by client. Required if you want to use the PKCE extension. YTQxYjYxOTRjOTEwMWYwNDNjZmE1ZDkzZTQ5YzU3MzE1YWRkZDliNjM4NGRiYzMwNDgyN2U2ZDA4Y2RiOGVkZg No
code_challenge_method The value is always S256, to indicate SHA256 hashing was used to generate the code_challenge. Required if you want to use the PKCE extension. S256 No

The full URL embedded in a hyperlink can look like this:

<a href="https://app.productboard.com/oauth2/authorize?client_id=hqAGVdAy9FZX5Ky5cBHUB2FshBdSO6eN75tWMX46ZZd
&response_type=code
&redirect_uri=https%3A%2F%2Fawesomesheet.com%2Foauth2-callback%3Ffoo%3Dbar
&state=4agg4zF76rwd3bBM
&code_challenge=YTQxYjYxOTRjOTEwMWYwNDNjZmE1ZDkzZTQ5YzU3MzE1YWRkZDliNjM4NGRiYzMwNDgyN2U2ZDA4Y2RiOGVkZg
&code_challenge_method=S256" target="_blank">Import features from Productboard</a>

After visiting the link, the user will have to select the Productboard workspace they want to authorize your application for and then (re)authenticate into Productboard. Then they will be presented with the authorization screen containing the information about your application, the permissions (scopes) it requires, and Deny and Authorize buttons:

Screenshot_2022-09-07_at_16.24.24.png

Once they press Authorize (if they press Deny - see Appendix: Error handling) they will be redirected to the redirect URI you registered for your application along with two extra query parameters:

Parameter Description Example value
code The generated authorization code T-hTGrKxVMJg4kJOdbmS1i7GDlGgmD-GED2kRwBqQ37
state The same value as sent in the authorization request (if present) 4agg4zF76rwd3bBM

So in our example case, the user could be redirected to the following URL:

https://awesomesheet.com/oauth2-callback?foo=bar&code=T-hTGrKxVMJg4kJOdbmS1i7GDlGgmD-GED2kRwBqQ37&state=4agg4zF76rwd3bBM

Your integration should listen to that URL and grab the authorization code from the query parameters.

Retrieving the access token

From this point, you no longer need any manual action from the user and everything should be automatically handled by your integration. You can exchange the authorization code received in the previous step for an access token by making POST request to app.productboard.com/oauth2/token with the following query parameters:

Parameter Description Example value Required
client_id Unique identifier of the application (received after registration) - random string hqAGVdAy9FZX5Ky5cBHUB2FshBdSO6eN75tWMX46ZZd Yes
client_secret Secret (password) for the application (received after registration) - random string N2C--2ceRZ7W0alDjx5W10m5wPIg-4PGD7nwrpPjyMe Yes
grant_type The value is always authorization_code to indicate we are using Authorization code grant authorization_code Yes
redirect_uri One of the registered redirect URIs (but URL-encoded). Must be an exact match. https://awesomesheet.com/oauth2-callback?foo=barhttps%3A%2F%2Fawesomesheet.com%2Foauth2-callback%3Ffoo%3Dbar Yes
code Authorization code T-hTGrKxVMJg4kJOdbmS1i7GDlGgmD-GED2kRwBqQ37 Yes
code_verifier String used to generate code_challenge in the authorization code request. Required if you want to use the PKCE extension. zR.emfeaE.vwRTgN-fU67C6gyT.2zDm7VuolFURfo.PtnNBxfjvmu8yKJ1-CBY.elqm6cvorfLNvT27detiWGh-cP0EuE7lIxQFPLoFbZA2nXI9Ib1nyEe875UjEBXze No

Example request URL:

https://app.productboard.com/oauth2/token?client_id=hqAGVdAy9FZX5Ky5cBHUB2FshBdSO6eN75tWMX46ZZd
&client_secret=N2C--2ceRZ7W0alDjx5W10m5wPIg-4PGD7nwrpPjyMe
&grant_type=authorization_code
&code=T-hTGrKxVMJg4kJOdbmS1i7GDlGgmD-GED2kRwBqQ37
&redirect_uri=https://awesomesheet.com/oauth2-callback?foo=barhttps%3A%2F%2Fawesomesheet.com%2Foauth2-callback%3Ffoo%3Dbar
&code_verifier=zR.emfeaE.vwRTgN-fU67C6gyT.2zDm7VuolFURfo.PtnNBxfjvmu8yKJ1-CBY.elqm6cvorfLNvT27detiWGh-cP0EuE7lIxQFPLoFbZA2nXI9Ib1nyEe875UjEBXze

If everything goes well, you should get JSON object with the following fields as a response:

Field Description Example value
access_token Access token in JWT format. Used for accessing Productboard public API. eyJ0eXAiOiJKV1QiLCJraWQ… (JWT)
token_type The value is always Bearer - indicates the access token should be used as Bearer token in the Authorization header Bearer
expires_in Number of seconds the access token is valid for from this moment. 86400
refresh_token Refresh token - random string. Used to get new access token once it expires. 4w4_-gHaOVixNuS_naAvqsRTsCuV7wWQgn0jXQYtUhs
refresh_token_expires_in Number of seconds the refresh token is valid for from this moment. 15552000
created_at UNIX timestamp denoting when these tokens were created. 1660051050

Example response:

{
   "access_token":"eyJ0eXAiOiJKV1QiLCJraWQiOiIwZjE5YzIyMjFhNmVlOWUwMDk3ZDliOTRkNzU4YWY0NGUyMDU1MDcxOTI2NTdhYzMzMDRhZjA2ZmIxY2MyMGNhIiwiYWxnIjoiUlM1MTIifQ.eyJpYXQiOjE2NjAwNTEwNTAsImlzcyI6ImU0NjljODdjLTI1NWQtNDMwYS05ZjcyLWFjODY5MzBjM2U5NSIsInN1YiI6IjI0ODM0NCIsInJvbGUiOiJhZG1pbiIsImF1ZCI6Imh0dHBzOi8vYXBpLnByb2R1Y3Rib2FyZC5pbmZvIiwidXNlcl9pZCI6MjQ4MzQ0LCJzcGFjZV9pZCI6IjQ2ODg2IiwiZXhwIjoxNjYwMTM3NDUxfQ.GsrpZb5ID6RtThijXed5RBolEByKxtURSmR4uSLaVeibcZpbzFZWBlN2zTFBkKFRqdYpfTlEr0GJrSc5jZOIp27yKIlvprEj2AW0FG9Zoj_N3V5Tv6f48oQ0x0q4PjAPiqQ2aE6swRYymMiufVqqFlpTlnypkUv7bVw1nDqsHG0zYb3Ha6kXHIGEhHR3RPVst1GspRZyqJo_Ml6N1S6dr5rDf6SxPmscopeEcJ1g9oKDjZTJ1A4wYHC33ZT7amE4VkedQcjAY2Gbslp7noAN9RTIW2vujU2eBJVFBye90dVZIxzoJbs5sGvzgOkUfT80Pbim1Zx-mVDBfLuThvZ5Dg",
   "token_type":"Bearer",
   "scope": "releases:read notes:create",
   "expires_in":86400,
   "refresh_token":"4w4_-gHaOVixNuS_naAvqsRTsCuV7wWQgn0jXQYtUhs",
   "refresh_token_expires_in":15552000 
   "created_at":1660051050
}
Important: The access token can then be used to access the Productboard API in the same way as the Public API access token generated inside Productboard. 
Warning: You won’t be able to obtain the access or refresh token without another manual authorization by user if you lose them, so make sure you store them securely

Refreshing the access token

The access token is short-lived (see Appendix: Credentials expirations ). Once it expires (you will get 401 - Unauthorized when making an API request), you need to refresh it using the refresh token you got in the previous step.

Warning: If your refresh token expires before you use it, the user will have to manually reauthorize the application.

The endpoint for refreshing the access token is app.productboard.com/oauth2/token and you need to provide the following query parameters:

Parameter Description Example value Required
client_id Unique identifier of the application (received after registration) - random string hqAGVdAy9FZX5Ky5cBHUB2FshBdSO6eN75tWMX46ZZd Yes
client_secret Secret (password) for the application (received after registration) - random string N2C--2ceRZ7W0alDjx5W10m5wPIg-4PGD7nwrpPjyMe Yes
grant_type The value is always refresh_token to indicate we are using Refresh token grant refresh_token Yes
refresh_token Refresh token 4w4_-gHaOVixNuS_naAvqsRTsCuV7wWQgn0jXQYtUhs Yes

You should receive a response in the same format as when Retrieving the access token, but with fresh access and refresh tokens. The refresh token you just used will expire 60 minutes after you use it (buffer in case you experience network issues, so you can retry).

Retrieving token information

To retrieve information about an active access token and its user, you can use the /oauth2/token/info endpoint.

Request

GET <https://app.productboard.com/oauth2/token/info?access_token=><TOKEN>

Request parameters

Parameter Description Required
access_token An active access token Yes

Successful response

Response code 200

{
  "application": {
    "uid": "HhmcWDaB37dRzxn-8LbPWIYHttIgAUg5dFJude6OIu8"
  },
  "resource_owner": {
    "name": "Guybrush Threepwood",
    "email": "guybrush@meleeisland.com"
  },
  "space": {
    "name": "Mêlée Island",
    "domain": "meleeisland"
  },
  "scopes": [
    "product_hierarchy_data:manage",
    "product_hierarchy_data:read",
    "releases:create",
    "releases:manage",
    "releases:read",
    "users:manage"
  ],
  "expires_in": 80746,
  "created_at": 1682056984
}

Revoking an access token

To revoke an access token you can use the /oauth2/revoke endpoint.

Request

POST <https://app.productboard.com/oauth2/revoke?client_id=><CLIENT_ID>&client_secret=<CLIENT_SECRET>&token=<TOKEN>

Request Parameters

Parameter Description Required
client_id Unique identifier of the application Yes
client_secret Secret (password) for the application Yes
token The active access token that will be revoked Yes

Successful Response

Response code 200

{}

OAuth2 applications management

Listing authorized applications for the workspace

To view authorized applications for their workspace, users can go inside their Productboard and head to Settings > Integrations page, where they will find Installed OAuth 2.0 integrations section. Here they can find useful information about the authorized applications - what are they about, what kind of access do they have, who (and when) authorized them for the workspace and when were they last used. Note that the application will be displayed here only after the user clicks the Authorize button and after the application exchanges the received authorization code for the access token.

Screenshot_2022-09-07_at_16.30.05.png

Revoking access to authorized application

In the section described above, maker with admin access can also revoke access to any authorized application listed there.

Deleting an OAuth2 application

The process of deleting an OAuth2 application for all the users is currently manual as well. Please fill in the deletion form and verify your ownership by sending us the Client ID and Client Secret you received after registration. After the request is approved, we will delete your application.

Appendix

Error handling

We follow the OAuth2 specification when it comes to error handling.

Errors during the initial authorization flow

The error code will be displayed to the user and if it makes sense it will be sent back to the application (to registered redirect URI) in error query parameter. List of the standard error codes is available here.

Screenshot_2022-08-10_at_10.00.05.png

Errors during the token requests

For errors that happen during server-to-server communication (access/refresh token requests) the error details will be sent encoded as JSON response to the integration (in error field). List of the standard error codes is available here.

Access Scopes

To limit access of the application and to increase the trust of the users, we require each application developer to explicitly state which kind of permissions the application requires. We do this by leveraging the OAuth2 scopes mechanism. The required permissions (scopes) along with their descriptions will be displayed to the user on the authorization screen before they authorize the application.

We generally support 3 categories of scopes:

  • Read scopes - allow to retrieve and list existing data and subscribe to webhooks.
  • Create scopes - allow to create new data.
  • Manage scopes - allow to update and delete existing data.

Below is the full list of the scopes supported at the moment:

Scope Description Admin Maker Contributor
product_hierarchy_data:read The application will be able to read all hierarchy entities (products, components, and features) and their attributes in your workspace. This includes the relationships between features, custom field values, releases, and Jira metadata.
product_hierarchy_data:create The application will be able to create all features and attributes in your workspace. This includes releases, roadmaps, and features.
product_hierarchy_data:manage The application will be able to edit and delete features and attributes in your workspace. This includes releases, roadmaps, and features.
custom_fields:read The application will be able to read hierarchy entity custom field definitions.
releases:read The application will be able to read releases and release groups.
releases:create The application will be able to create releases and release groups.
releases:manage The application will be able to edit and delete releases and release groups.
notes:create The application will be able to create notes.
users:read
The application will be able to list users.
users:manage The application will be able to edit (note creating) users
users_pii:read The application will be able to read personally identifying information (names, email addresses, etc.) from (note-creating) users.
members_pii:read The application will be able to read personally identifying information (names, email addresses, etc.) from your Productboard users.
plugin_integrations:manage The application will be able to introduce and manage a UI plugin on your Productboard space.
objectives:read The application will be able to read objectives.
Note: Some Productboard user roles are allowed to authorize only a subset of the OAuth2 scopes. For a Productboard user to be able to authorize an OAuth2 application, their role must be allowed to authorize all the scopes the application is requesting.

Example 1: If a Maker tries to authorize an OAuth2 application requesting notes:create and users:read scopes, it will work as the Maker role is allowed to authorize both scopes.
Example 2: If a Maker tries to authorize a different application requesting notes:create, users:read and releases:manage scopes, it will fail because the Maker role is not allowed to authorize the releases:manage scope.

Credentials expirations

For security reasons, most of the credentials used within the OAuth2 authorization flow will expire after some time, and you need to refresh them. Below is the table listing all the credentials and their expiration times.

Credential Expiration How to refresh it
Client Secret Never -
Authorization code 10 minutes (or immediately after being used) Manual reauthorization by user
Access token 24 hours Refresh token
Refresh token 180 days (or 60 minutes after being used) Refresh token / Manual reauthorization by user

Feedback

If you have any questions or feedback regarding OAuth2 in Productboard, please reach us at oauth2@productboard.com.

Was this article helpful?
1 out of 4 found this helpful

Comments

0 comments

Article is closed for comments.

Articles in this section

Our Support hours:
Monday to Friday from 9:00 am - 2:00 am CET. Monday to Friday from 0:00 am - 5:00 pm PST.
Productboard Academy
Become a Productboard expert with self-paced courses, quick tip videos, webinars and more.
Product Makers Community
Connect with product leaders, share and find product jobs, and learn how to approach similar challenges. Come join our Product Makers community.