OAuth Tokens

While API Keys are a quick and convenient way to make API requests from your third-party application in a machine-to-machine setting, sometimes you may want to authorize each user individually with a unique access token for each. This allows you to get the user context for specific users and require each user to authenticate with Pitchly before using Pitchly data in your application.

To get user-specific access tokens, you can use Pitchly's OAuth authorization code flow. OAuth is a global authorization standard for sharing data from one application to another. You can find an example of how this flow generally works here.

Below is a description of each step in the OAuth authorization code flow (and refresh token flow).

Initialize OAuth flow

This endpoint is triggered by the user opening this page in their browser with the following query parameters in the URL. The user will be presented with the option to authorize your app access to the user's Pitchly account. If approved, your app will receive an authorization code in return. In the next request, you will exchange that code for an actual access token via a server-side call.

Initialize OAuth flow

GET https://v2.pitchly.net/oauth/authorize

Redirect the user to this URL with the following query parameters to start the OAuth flow. Once the user approves access (or if they have already approved), the user will be redirected to the appropriate redirect URI (specified in the app's configuration) with an authorization code that can be exchanged for an access token.

Query Parameters

NameTypeDescription

response_type*

String

"code"

client_id*

String

App ID

redirect_uri

String

One of the redirect URIs provided when you configured your app. Note that it must match exactly. If one is not provided, the first one configured for your app is assumed.

state

String

A random string that will be returned back to your redirect URI as a query parameter. If the returned state matches the state originally used at the start of the OAuth flow, you can validate that the request has not been forged (see CSRF attacks).

organization_id

String

If provided, this organization will be selected by default for the user. If the app is already approved for the user on this org, the user will also be immediately redirected back to the app with a valid code. For an app to be approved, an admin must have already allowed the app on the org.

force_prompt

String

If set to "true", "yes", or "1", the user will always be prompted to allow the app, even if organization_id is provided and the app is already approved.

https://example-app.com/cb?code=Yzk5ZDczMzRlNDEwY&state=5ca75bd30

Exchange auth code for access token

Call this from your application's server side to exchange the authorization code returned by the previous request for an access token. You can then provide this access token in GraphQL API requests in the accessToken variable. When using a user-specific access token, replace all instances of secretKey in your GraphQL requests with accessToken, and provide your access token within it.

Do not call this endpoint from the client side, since the request contains your application's secret key. You should never make your secret key accessible client side.

Exchange authorization code for access token

POST https://v2.pitchly.net/api/oauth/access_token

Call this on your backend to exchange the authorization code acquired from the first step for an access token, which you can use to make GraphQL API requests.

Headers

NameTypeDescription

content-type*

String

"application/x-www-form-urlencoded"

accept*

String

"application/json"

Request Body

NameTypeDescription

grant_type*

String

"authorization_code"

code*

String

The authorization code returned as a query param in the response of the previous request.

client_id*

String

App ID

client_secret*

String

App Secret

{
    access_token: "gRSgnFX1AhHTsCmkmE-SpRA3ViNYb8XN2-Kys1yfNZA",
    expires_in: 7200, // seconds until access token expiration
    refresh_token: "_Wv-VoCpm2rq3VsWnAMR3jZzkk-VimqLKEDiUujzjEn"
}

Refresh access token (optional)

This step is optional and only applies if you wish to continue making API calls to Pitchly while the user is offline, or if you would like to continue making API requests without sending the user back through the OAuth flow after the token expires in 2 hours.

Whenever you receive a token-invalid error from a GraphQL API request, call this endpoint to get a new access token and retry the request. You will need a refresh token either from the previous request or from the result following this request.

While refresh tokens do not expire over time, they do expire as soon as they're used. If you wish to refresh access tokens, we recommend storing the refresh token in your database until it is ready to be used, and once exchanged, swap it with the new refresh token for the next refresh.

Refresh access token

POST https://v2.pitchly.net/api/oauth/access_token

Call this to exchange a refresh token for a new access token and refresh token.

Headers

NameTypeDescription

content-type*

String

"application/x-www-form-urlencoded"

accept*

String

"application/json"

Request Body

NameTypeDescription

grant_type*

String

"refresh_token"

refresh_token*

String

Refresh token, returned in the previous request or when rerunning this request.

client_id*

String

App ID

client_secret*

String

App Secret

scope

String

A space-delimited list of permissions to downscope the resulting access token to. Note that the refresh token will still possess full permissions and can be used to generate more access tokens with elevated permissions, but the access token returned in this request will be downscoped, allowing you to pass it to a client with limited permissions. Possible values are: readData, insertData, updateData, deleteData, addFields, and readMembers (see Permissions for details). By default, not providing a scope will fall back to full permissions allowed for the app.

{
    access_token: "WE5vGFit3tkB1iU131_RPmQp6Z2OwR17jeyn2gfp3mn",
    expires_in: 7200, // seconds until access token expiration
    refresh_token: "bkdy8v6A3L_NetN_V5G3jYFNax4X9ljYVL-prGoz822"
}

Serverless flow

If you wish to use OAuth to acquire user-specific access tokens but don't have a sever side to exchange an authorization code for an access token, you can alternatively use the implicit flow to get an access token directly instead of an authorization code.

This method is not recommended if you do have a server side with which you can exchange authorization codes because it is slightly less secure than the authorization code flow described above. This method should only be used if you do not have a server side that can keep a secret, such as in the case of a single-page application (SPA) that does not have a server or a native mobile or desktop app.

To initiate the implicit flow, send the user to this endpoint:

Initialize implicit OAuth flow

GET https://v2.pitchly.net/oauth/authorize

Redirect the user to this URL with the following query parameters to start the OAuth flow. Once the user approves access (or if they have already approved), the user will be redirected to the appropriate redirect URI (specified in the app's configuration) with an access token.

Query Parameters

NameTypeDescription

response_type*

String

"token"

client_id*

String

App ID

redirect_uri

String

One of the redirect URIs provided when you configured your app. Note that it must match exactly. If one is not provided, the first one configured for your app is assumed.

state

String

A random string that will be returned back to your redirect URI as a query parameter. If the returned state matches the state originally used at the start of the OAuth flow, you can validate that the request has not been forged (see CSRF attacks).

organization_id

String

If provided, this organization will be selected by default for the user. If the app is already approved for the user on this org, the user will also be immediately redirected back to the app with a valid token. For an app to be approved, an admin must have already allowed the app on the org.

force_prompt

String

If set to "true", "yes", or "1", the user will always be prompted to allow the app, even if organization_id is provided and the app is already approved.

https://example-app.com/cb?token_type=Bearer&access_token=_t9MkUKCnQxgYg1LsIrQuNT-TkKVY2kBCgWLPmGnF7D&expires_in=7200&state=5ca75bd30

If you do not have a server side, you will not be able to utilize refresh tokens to generate new access tokens once they expire because a secret cannot be kept. Instead, you will need to send the user back through this OAuth flow after the access token expires, so you can receive a new access token. By default, access tokens expire after 2 hours.

In future versions of Pitchly, you will not need to forward the user back through the OAuth flow to refresh access tokens on public clients (such as SPAs). Future versions of Pitchly will instead recommend always using the authorization code flow with PKCE (a new standard for generating dynamic secrets for a public client), which will allow you to exchange an auth code for an access token and refresh token entirely client side using a dynamic secret instead of a fixed secret which we use today.

Last updated