Back

How to build a public Planning Center integration: Building the Auth Flow

Aug 16, 20247 minute read

Introduction

Hey there, fellow developer! Ready to dive into the world of Planning Center integrations? You're in the right place. Today, we're going to tackle one of the most crucial aspects of building a public integration: the authorization flow. Planning Center's API is a powerful tool, but without proper authorization, you're not going anywhere. So, let's roll up our sleeves and get this auth flow nailed down!

Prerequisites

Before we jump in, make sure you've got:

  • A Planning Center Developer account (if you don't have one, go grab it!)
  • Node.js installed on your machine
  • Your favorite web framework (we'll be using Express in our examples, but feel free to adapt)

Setting up the project

First things first, let's get our project set up:

mkdir planning-center-integration cd planning-center-integration npm init -y npm install express axios dotenv

Now, let's create a basic server setup in index.js:

require('dotenv').config(); const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Planning Center OAuth 2.0 Flow

Planning Center uses OAuth 2.0 with the authorization code grant. Don't worry if that sounds like a mouthful – it's just a fancy way of saying "we're going to send users to Planning Center, they'll approve our app, and then we'll get a special code to access their data."

Implementing the Authorization Request

Let's add a route to start the auth process:

app.get('/auth', (req, res) => { const authUrl = `https://api.planningcenteronline.com/oauth/authorize?client_id=${process.env.CLIENT_ID}&redirect_uri=${encodeURIComponent(process.env.REDIRECT_URI)}&response_type=code&scope=people`; res.redirect(authUrl); });

When users hit this route, they'll be whisked away to Planning Center's authorization page. Magic!

Handling the Authorization Callback

Now, let's set up a route to handle the callback:

app.get('/callback', async (req, res) => { const { code } = req.query; if (!code) { return res.status(400).send('Authorization code missing'); } // We'll use this code in the next step // For now, let's just acknowledge we got it res.send('Authorization successful! Check the console.'); console.log('Authorization code:', code); });

Exchanging the Code for Access Token

Time to trade in that code for an access token:

const axios = require('axios'); // ... inside your callback route try { const response = await axios.post('https://api.planningcenteronline.com/oauth/token', { grant_type: 'authorization_code', code, client_id: process.env.CLIENT_ID, client_secret: process.env.CLIENT_SECRET, redirect_uri: process.env.REDIRECT_URI }); const { access_token, refresh_token } = response.data; // Store these securely! We're just logging for demo purposes console.log('Access Token:', access_token); console.log('Refresh Token:', refresh_token); } catch (error) { console.error('Error exchanging code for token:', error.response.data); res.status(500).send('Error obtaining access token'); }

Refreshing the Access Token

Access tokens don't last forever. Here's how to refresh them:

async function refreshAccessToken(refresh_token) { try { const response = await axios.post('https://api.planningcenteronline.com/oauth/token', { grant_type: 'refresh_token', refresh_token, client_id: process.env.CLIENT_ID, client_secret: process.env.CLIENT_SECRET }); return response.data.access_token; } catch (error) { console.error('Error refreshing token:', error.response.data); throw error; } }

Making Authenticated Requests

Now that we have our access token, let's use it:

async function getPeople(access_token) { try { const response = await axios.get('https://api.planningcenteronline.com/people/v2/people', { headers: { Authorization: `Bearer ${access_token}` } }); return response.data; } catch (error) { if (error.response && error.response.status === 401) { // Time to refresh that token! console.log('Token expired, refreshing...'); // Implement your refresh logic here } throw error; } }

Best Practices

  • Never, ever, ever store your client secret in your code. Use environment variables!
  • Implement PKCE (Proof Key for Code Exchange) for added security, especially for mobile or single-page apps.
  • Always handle token expiration gracefully.

Conclusion

And there you have it! You've just implemented a robust auth flow for your Planning Center integration. From here, you can start building out the rest of your app's functionality. Remember, a solid auth implementation is the foundation of any good integration.

Additional Resources

Now go forth and build something awesome! Your Planning Center integration awaits. Happy coding!