Back

How to build a public Tally integration: Building the Auth Flow

Aug 11, 20249 minute read

Hey there, fellow JavaScript enthusiast! Ready to dive into the world of Tally integrations? Today, we're going to tackle one of the most crucial parts of building a public integration: the authorization flow. Buckle up, because we're about to make your Tally integration dreams come true!

Introduction

Tally is an awesome tool for creating forms and surveys, and building an integration with it can open up a world of possibilities. The auth flow is the gatekeeper of your integration, ensuring that users can securely connect their Tally accounts to your app. We'll be focusing on creating a smooth, user-friendly auth flow that'll make your integration shine.

Prerequisites

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

  • Node.js and npm installed (you're a JS dev, so I'm sure you've got this covered!)
  • A Tally developer account and API credentials
  • Your favorite code editor ready to rock

Setting up the project

Let's get this party started! Create a new directory for your project and initialize it:

mkdir tally-integration cd tally-integration npm init -y

Now, let's install the essentials:

npm install express axios dotenv

Understanding Tally's OAuth 2.0 flow

Tally uses OAuth 2.0 for authorization, which is like a secret handshake between your app and Tally. Here's the basic flow:

  1. Your app redirects the user to Tally's authorization page
  2. The user grants permission
  3. Tally redirects back to your app with an authorization code
  4. Your app exchanges this code for an access token
  5. You use this token to make API requests on behalf of the user

Simple, right? Let's make it happen!

Implementing the authorization request

First, let's create a route that'll kick off the auth process:

const express = require('express'); const app = express(); app.get('/auth', (req, res) => { const authUrl = `https://tally.so/oauth/authorize?client_id=${process.env.TALLY_CLIENT_ID}&redirect_uri=${encodeURIComponent(process.env.REDIRECT_URI)}&response_type=code`; res.redirect(authUrl); });

When a user hits this route, they'll be whisked away to Tally's authorization page. Magic!

Handling the callback

Now, let's set up the endpoint that Tally will redirect back to:

app.get('/callback', async (req, res) => { const { code } = req.query; // We'll use this code in the next step // For now, let's just acknowledge it res.send('Authorization successful! You can close this window.'); });

Exchanging the code for an access token

Time to trade that code for the real treasure - an access token:

const axios = require('axios'); async function getAccessToken(code) { const response = await axios.post('https://tally.so/oauth/token', { client_id: process.env.TALLY_CLIENT_ID, client_secret: process.env.TALLY_CLIENT_SECRET, code, grant_type: 'authorization_code', redirect_uri: process.env.REDIRECT_URI }); return response.data.access_token; }

Now, update your callback route to use this function:

app.get('/callback', async (req, res) => { const { code } = req.query; try { const accessToken = await getAccessToken(code); // Store this token securely - we'll talk about this soon! res.send('Authorization successful! You can close this window.'); } catch (error) { res.status(500).send('Oops! Something went wrong.'); } });

Refreshing the access token

Access tokens don't last forever, so let's implement a refresh mechanism:

async function refreshAccessToken(refreshToken) { const response = await axios.post('https://tally.so/oauth/token', { client_id: process.env.TALLY_CLIENT_ID, client_secret: process.env.TALLY_CLIENT_SECRET, refresh_token: refreshToken, grant_type: 'refresh_token' }); return response.data.access_token; }

Securing the token storage

Storing tokens is like handling dynamite - treat them with care! Here's a simple (but not production-ready) example using environment variables:

require('dotenv').config(); // Storing process.env.ACCESS_TOKEN = accessToken; // Retrieving const storedToken = process.env.ACCESS_TOKEN;

In a real-world scenario, you'd want to use a secure database and encrypt these tokens. Stay safe out there!

Making authenticated requests to Tally API

Now that we've got our golden ticket (the access token), let's use it:

async function getForms(accessToken) { const response = await axios.get('https://api.tally.so/v1/forms', { headers: { Authorization: `Bearer ${accessToken}` } }); return response.data; }

Error handling and edge cases

Always be prepared for things to go sideways. Here's a quick example of error handling:

try { const forms = await getForms(accessToken); console.log(forms); } catch (error) { if (error.response && error.response.status === 401) { // Time to refresh that token! const newToken = await refreshAccessToken(refreshToken); // Try the request again with the new token } else { console.error('An unexpected error occurred:', error.message); } }

Testing the auth flow

Before you pop the champagne, make sure to thoroughly test your auth flow. Try different scenarios:

  • Happy path (everything works)
  • User denies permission
  • Invalid tokens
  • Network errors

Conclusion

And there you have it, folks! You've just built a rock-solid auth flow for your Tally integration. Remember, this is just the beginning - there's a whole world of Tally API endpoints waiting for you to explore.

Keep coding, keep learning, and most importantly, keep having fun! Your Tally integration journey is just getting started, and I can't wait to see what you'll build next. Happy coding!