Dev

Authenticating with 3rd Party Services

Jun 16, 2015

I’ll be honest—authentication is not an exciting topic. I thought about skipping this post, but then I realized that this subject is often left out of blog posts. Either the post is about everything after authentication or the author realizes that authentication is an entire post on its own, so they write a quick paragraph and link to another article. After all I’ve been through with integrations, it would be a disservice to myself and others to skip this post—I’ve learned too much, and I need to share this knowledge!


The first thing to know about authenticating with a 3rd party service is that there are multiple methods for doing so, and it’s up to the service to decide which method you must use. Newer services will often start by providing a simpler method of authentication, like BasicAuth with an API key, while more veteran services will offer more user-friendly authorization flows, like OAuth. Both serve the purpose of authenticating with the service, but one is easier on the dev while the other is easier on the user.

authorizing-integrations-oauth

If a service looks appealing enough to integrate with, there’s a good chance it’s using one of the more serious methods of authentication. I say this because integrations are a real commitment, and if the service really wants you to tie your app so closely to theirs, they’ve probably gone the extra mile to support one of the open standards of authentication.

In my own experience, BasicAuth often means “Yes, we have an API. You can play with it if you want,” while OAuth2 means “Our business relies on integrations as a selling point. Here’s our documentation, support center, and IRC channel.” Occasionally, you’ll find a neglected service with forced support for OAuth or a solid service that doesn’t need anything more than BasicAuth, but the authentication method is often a good indicator of how smooth this ride will be.

authorizing-integrations-documentation

With Cushion, I started out by integrating with the heavy hitters of the freelance industry—Harvest and FreshBooks. Both support OAuth, which is great, but each supports a different version of the standard, which is not great. Harvest offers authentication through OAuth2, which directs the user through an authorization flow and provides the dev with an access token and a refresh token. The access token expires after 18 hours, so the dev will eventually need to request a new access token using the refresh token. This is a bit of extra work, but it keeps the token somewhat fresh, in case the access token lands in the wrong hands.

FreshBooks, the older of the two services, offers authentication through OAuth1, the older standard. To the user, the authorization flow is the same, but to the dev, there’s no expiration on the access token. Once the dev receives the token, they’re good to go indefinitely, until the user deauthorizes the integration. OAuth1 is definitely easier on the dev, but not as secure. Then again, an 18-hour expiration period sort of defeats the purpose of an expiring token.

authorizing-integrations-custom

At first, I built an authorization system from scratch using the OAuth and OAuth2 gems. After authorizing, Cushion would show a sleek progress screen as it moved through each step before retrieving the tokens. For anyone using Cushion, it looked seamless, but under the hood, it was a mess. I could easily imagine this system becoming a headache with each new service I added—especially if it introduced a new authorization method. After wrapping up Harvest, it finally dawned on me that another solution existed—a much easier one. I still kick myself for forgetting the OmniAuth gem, but in a single afternoon, I was able to replicate the same system I spent weeks implementing. I can’t get those weeks back, but at least I caught myself before I wasted even more time.

For those unfamiliar with OmniAuth, it abstracts the authorization process through the use of “strategies”. The strategy tells OmniAuth which authentication method the service uses and then formats the service’s response into standardized payloads. The user payload includes the user’s ID, name, email, etc., while the credentials include the access token and optional refresh token. With OmniAuth, authorizing with a new service is as easy as installing its strategy. Though OmniAuth is more commonly used during the sign up process, it works surprisingly well with integrations, too.

Now that I had OmniAuth handling the authorization flow, I needed to safely store the access tokens. Access tokens don’t seem as precious as passwords, but considering they grant access to users’ account, they should be protected just the same. I store access tokens in an encrypted column on the authorization model, which bridges the gap between the user and the 3rd party service. To enable an integration, I simply need to pass it the authorization model—nothing more.

authorizing-integrations-authorizations

Currently, Cushion only allows one authorization per service, but I quickly learned that many users have multiple accounts for a single service. Since services like Harvest are used by both freelancers and companies, clients will often invite freelancers to be a guest on their account to streamline the delivery of hours and invoices. Some freelancers also invite their subcontractors to use their account for the same reason.

authorizing-integrations-multiple-authorizations

Luckily, the changes required to make multiple authorizations happen are minimal. I built the integration system in a way that allows for multiple authorizations from the start—I just need to design the front-end to handle them. This will entail asking the user which account to use whenever enabling an integration and providing the ability to delete authorizations from the table view. If I end up including any additional details with authorizations, like activity, I might be able to justify a new page for an individual authorization. At the moment, though, the table view will suffice.

Share this on Twitter or Facebook

Archive

  1. My Typical Week as a Startup Founder
    Story
  2. Building Components in a Sandbox
    Dev
  3. Reactive Time with Vue.js
    Dev
  4. Visualizing Daylight Saving Time
    Dev
  5. Recording Screencast GIFs
    Dev
  6. Writing a Job Listing
    Story
  7. Using Feature Flags to Run Betas
    Dev
  8. Our First Company Lunch
    Story
  9. How to embed Vue.js & Vuex inside an AngularJS app... wait what?
    Dev
  10. Funding Cushion
    Story
  11. Hiring a Team of Freelancers
    Story
  12. Taking a Real Break From Work
    Story
  13. Slack as a Notification Center
    Dev
  14. Document Your Features
    Story
  15. 300
    Story
  16. Vacations
    Design
  17. Offering Discounts
    Design
  18. Waves of Traffic
    Story
  19. Less Blogging, More Journaling
    Story
  20. Retention Through Useful Features
    Design
  21. The Onboarding Checklist
    Design
  22. Spreading the Word
    Story
  23. From Beta to Launch - The Subdomain
    Dev
  24. From Beta to Launch - Sign up
    Design
  25. From Beta to Launch - Messaging
    Design
  26. Launch
    Story
  27. Authenticating with 3rd Party Services
    Dev
  28. Intro to Integrations
    Design
  29. Inspiration vs Imitation
    Story
  30. The Emotional Rollercoaster
    Story
  31. Designing Project Blocks
    Design
  32. Everything in Increments
    Story
  33. Deleting Your Account
    Design
  34. Designing the Subscription Page
    Design
  35. Rewriting the Timeline
    Dev
  36. Restructuring the Individual Project Page
    Design
  37. Project Blocks
    Story
  38. Redesigning the Homepage
    Design
  39. Multiple Timelines
    Design
  40. Archiving and Estimate Differences
    Design
  41. Multiple Financial Goals
    Design
  42. Zooming in on the Timeline
    Design
  43. Currency
    Dev
  44. Preferences, Accounts, and a Typeface Change
    Design
  45. Sending Out the First Email
    Story
  46. Currency Inputs, Notifications, and Invoice Nets
    Design
  47. Dots and Lines
    Design
  48. Calculating in the Database and Revealing Tendencies
    Dev
  49. Improved Form UX
    Design
  50. Cushion is Online
    Story
  51. Schedule Timeline Patterns
    Design
  52. A Slimmer Schedule Timeline
    Design
  53. The Schedule Timeline
    Design
  54. Plugging in Real Data for the First Time
    Design
  55. Transitions and Project Lists
    Design
  56. Death to Modals
    Design
  57. The Individual Project Page
    Design
  58. Estimated Incomes and Talks with Other Freelancers
    Story
  59. Statuses to Lists and the Paid Beta
    Story
  60. The Timeline
    Story
  61. Invoice Terminology
    Dev
  62. Modal Forms
    Dev
  63. Wiring the Backend to the Frontend
    Dev
  64. Balancing Design and Dev
    Story
  65. Timecop, Monocle, and Vagrant
    Dev
  66. Going with Ruby and Sinatra
    Dev
  67. Ditching local-first and trying out Node.js
    Dev
  68. Switching to AngularJS
    Dev
  69. Building the Table with Vue.js
    Dev
  70. Clients, Projects, and Invoices
    Dev
  71. Introduction
    Story

Ask a Freelancer

A podcast series where experienced freelancers answer questions about freelancing.

Listen to the Podcast

Talking Shop

An interview series where we talk to freelancers about important topics in the freelance world.

Read the Interviews

Running Costs

Take a close look at the costs that go into running a web app and why we use specific services.

View the Costs

How It’s Made

Follow along with the journal for insight into the overall experience of building an app.

Read the Journal