API
⌘K
My Developer Account

Add-ons and OAuth

Your add-on will need to make authenticated requests to both Planning Center's API and your application's API. To do so, we make use of OAuth 2.0's "Authorization Code" Flow.

At a minimum, there will be two OAuth Providers: Planning Center and your application, as well as two OAuth applications: one you register with us here to make requests to Planning Center, and one you create in your application and configure for Planning Center in your add-on config file to make requests to your API.

Once configured, we perform the OAuth flow for both providers (Planning Center and you) when your add-on is loaded. The end result is your add-on's JavaScript code will have access to an authenticatedFetch function for making requests to Planning Center's API, and an authenticatedIntegratorFetch function for making requests to your API. More details on those functions can be found here.

Two-way OAuth Handshake

Note: Fully detailing OAuth is beyond the scope of this documentation. If you're looking for those details, here's a place to start. It's worth noting, as far as add-ons are concerned we only use the "authorization code" flow. Also, most frameworks have libraries that you can leverage for most (if not all!) of the heavy lifting.

Since, add-ons must communicate with both Planning Center's API and your API, we need a two-way OAuth handshake. For the purpose of this documentation, let's suppose your application is running at https://example.com and Planning Center is of course running at https://api.planningcenteronline.com. Let's further suppose your app has the following endpoints:

  • GET https://example.com/oauth/pco/complete

    • Once the user has allowed your app to access Planning Center's API, we redirect the user here with an authorization_code. Your server can exchange that authorization_code for an access_token by POSTing to https://api.planningcenter.com/oauth/token with that code and your client credentials. Once, you're done, you must redirect to https://api.planningcenteronline.com/addons/authorizations/:oauth_application_id/advance.

    This is worth calling attention to as a non-standard part of the OAuth flow, but it's essential to the two-way OAuth handshake we use for add-ons. You don't have to use this exact url -- it's configurable in your config.yaml file. However, you do have to redirect to Planning Center at that exact /advance url so we can begin the second leg of the two-way handshake. That's where Planning Center will request an OAuth token from you.

  • GET https://example.com/oauth/authorize

    • This is the page that prompts the user to allow Planning Center to access your API. If the user is not already logged into your system, you should do that before showing them this prompt. Generally, this prompt is a form that POSTs back to the same endpoint.

  • POST https://example.com/oauth/authorize

    • Assuming the user allowed Planning Center to access, this endpoint creates an authorization_code and redirects back to Planning Center with that authorization_code.

  • POST https://example.com/oauth/token

    • This is the endpoint that receives the POST request to convert the authorization_code into an access_token. We will also use this endpoint to refresh a token if the token is about to expire. (Token expiration is optional and up to you. If there is an expiration value present, then we will refresh the token a few minutes before it expires.)

Step 0: Clicking the Authorize Button

When your add-on is first initialized, the user is presented with an "Authorize" button. Clicking it begins the two-way OAuth handshake.

Initially unauthorized add-on

Step 1: Redirect to https://api.planningcenteronline.com/oauth/authorize

First, you get a token to Planning Center. The user is presented with an authorization prompt like this:

Planning Center authorization prompt

Step 2: Redirect to https://example.com/oauth/pco/complete

This is configurable per environment via the redirect_url in your config.yaml file.

Once the user allows your app to access Planning Center, they're redirected here. This redirect will include an authorization_code. As stated, your server can exchange that authorization_code for an access_token to Planning Center's API, but you don't have to. However, once you're done, you must redirect to https://api.planningcenteronline.com/addons/authorizations/:oauth_application_id/advance

The :oauth_application_id is an integer ID that represents your application in our system. This is not the client_id. You can find it by going to https://api.planningcenteronline.com/oauth/applications, clicking edit, and noting the ID from the URL. For example, if the URL is https://api.planningcenteronline.com/oauth/applications/42/edit, then your oauth_application_id is 42.

Step 3: Redirect to https://api.planningcenteronline.com/addons/authorizations/:oauth_application_id/advance

At this point, both you and Planning Center have an access_token that can be used to make requests to Planning Center's API. Now, we need to do the same for your API so the add-on can make requests to it. Just like the user had to allow you to access Planning Center's API, they now are given an opportunity to allow Planning Center to access your API.

Step 4: Redirect to https://example.com/oauth/authorize

This is configurable per environment via the authorize_url in your config.yaml file.

Much like Step 1, the user is presented with a prompt. What that looks like is up to you, but as an example it could look something like this:

Integrator authorization prompt

That prompt will POST back to http://example.com/oauth/authorize where your server will generate an authorization_code and send it to Planning Center by redirecting the user.

Step 5: Redirect to https://api.planningcenteronline.com/addons/authorizations/:oauth_application_id

Planning Center will POST that authorization_code and the client credentials you configure in your add-ons config.yaml, to exchange them for an access_token that can be used to make requests to your API.

Step 6: POST to https://example.com/oauth/token

This is configurable per environment via the token_url in your config.yaml file.

Your server validates the authorization_code and the client credentials, and issues an access_token.

That concludes the two-way OAuth handshake. Planning Center will close the window it used for redirecting and prompting the user, and your add-on will be ready for use!

Best Practices

Use a Library

There's little reason to implement the OAuth protocol yourself. You'll generally need to implement the OAuth protocol both from the perspective of an "OAuth Provider" (to issue access_tokens to Planning Center) and an "OAuth Client" (to request an access_token from Planning Center). Most web frameworks will have well-established libraries for both pieces. For example, in Rails we have doorkeeper for the OAuth provider piece, and the oauth2 library for the OAuth Client piece.

Create a Separate OAuth Application for Your Add-on

Many add-on authors already have an existing integration with Planning Center as a part of their offering. Don't reuse that for your add-on! Even if you have an existing OAuth application, we recommend you create a new one just for your add-on so tokens and logs are kept separate.

Don't Save access_tokens You Don't Need To

In Step 2 when we redirect to https://example.com/oauth/pco/complete, we'll include an authorization_code in that redirect you can exchange for an access_token, but you might not have to.

Even if you don't, we'll make an access_token available to your the frontend code of your add-on via the authenticatedFetch function.

You probably don't need to if you have an existing OAuth application. Your server can continue to levearge that existing integration. This is ideal because then the requests your add-on's UI makes to Planning Center are grouped separately from the requests your server makes to Planning Center in our logs, which can aid in troubleshooting.

You might not need to if your feature doesn't need Planning Center's data. For example, if you're building a texting service and all you need is a phone number, your add-on's frontend can fetch that phone number using authenticatedFetch, and pass it to your API via authenticatedIntegratorFetch.

Store Tokens Securely

When you do need to store access_tokens and refresh_tokens, you must do so securely. Remember, these all have privileged access to our shared customer's data inside Planning Center.

  • Never store the client_secret, access_token or refresh_token in a mobile application or on any public client.

  • access_tokens and refresh_tokens can be stored in a secure database. When they are, they should be encrypted using a strong encryption standard such as AES. Also, avoid storing the client_secret in the same database as the refresh_token, because compromising both allows an attacker to request new access_tokens.

  • Never put your client_secret in source code. Instead, use an environment variable to reference the secret in your application.

Authorization Flow

This is the general flow of activating and authorizing an add-on from with in Planning Center as a flow chart. It includes the two-way OAuth handshake, as well as what needs to happen before and after:

Add-on authorization flow chart