× FreshBooks App Logo
Official App
Free - Google Play
Get it
You're currently on our US site. Select your regional site here:

Get Authenticated On The FreshBooks API

You want to connect your app with FreshBooks so that you or FreshBooks customers can use your app. We’ll start this tutorial with the expectation that you already have a FreshBooks account (trial or paid), have read through the introduction and created an app and an https redirect URI.

FreshBooks provides OAuth 2.0 authorization code grant flow to authenticate on the FreshBooks api.

Authorization Code Grant Flow Explained

The OAuth authorization code grant flow is a way for a user to grant your application access to their account without ever having to provide you with their password. Y

our application will send the user to an Authorization URL, which is a FreshBooks page where the user can login, at which point they are prompted to approve your application. When they do, their browser is sent to a redirect URI to your site that you provide containing an authorization code in the request parameters. Your application can then make a call to FreshBooks with this authorization code, at which point we return a Access Token which is good for making calls to the API for that user.

In this way, the user’s login information is only entered into FreshBooks and not shared, and the Access Token is requested directly by you from FreshBooks so it also cannot be intercepted in the browser.

The Access Token expires after 12 hours, however the Authorization Response also contains a Refresh Token (which never expires, but can only be used once) that can be used to request a new Access Token (and a new Refresh Token for the next refresh request)

FreshBooks Oauth2.0 Flow

Some more links if you want to dig into OAuth 2.0 further:

Using the FreshBooks Authorization Grant Flow

Navigate to the developer portal and select your application.

Then, scroll to the bottom under ‘App Settings’ and copy your authorization url. The format of your authorization url is:

Authentication URL
  1. Your app must redirect users to the authentication page to start the authentication process. The user reviews your app, the scopes it requests and provides consent to access their FreshBooks data on their behalf by clicking ‘Allow.’
Authorization Dialog
  1. Once the user clicks ‘Allow,’ FreshBooks redirects the user to the redirect URI specified with a ‘code‘ query parameter. This is your authorization code. Make sure your app server is actively listening for requests on your redirect uri.
authorization code
  1. As soon as your app receives the authorization code, your app must request a access token using the code parameter retrieved above along with your client_id, client_secret, redirect_uri. Keep in mind the authorization code expires in 5 minutes.
curl -L -X POST 'https://api.freshbooks.com/auth/oauth/token' \
-F 'grant_type="authorization_code"' \
-F 'client_id="943f08ec5a5797f579e2682103868216f2d00a64faf0fb36e8257c8acceebfc6"' \
-F 'client_secret="<APP_CLIENT_SECRET>"' \
-F 'code="6ccc545aecf51e5cbe9fc37da025281bc9e7662a1b7b1b492e67a3aa94b66021"' \
-F 'redirect_uri="https://b425-143-178-154-232.ngrok.io/settings"'
  1. You will receive an access token (which you will use a the bearer token to authenticate requests) and a refresh token in the response below. Make sure to store these tokens securely to be retrieved later.
    "access_token": "eyJraWQiOiJhMTlPSlR5aVlKOXhPM3FoWnhWeE1KZE5ZNXJ4cUhpQzBSTUY0TWRheGtjIiwiYWxnIjoiUlMyNTYifQ.eyJqdGkiOiJiY2U1M2Y0NTNlMTVmNTM5MzJjYTQPwzR2-W1GOmodMQl7Nwtc3Gkc-1gXtPQYFixBrdQg",
    "token_type": "Bearer",
    "expires_in": 43200,
    "refresh_token": "f8cddb919402989a72918f55a8fe31f36f353d409e018781d0f59c44e1e59e03",
    "scope": "user:profile:read user:expenses:read user:expenses:write user:clients:read user:clients:write",
    "created_at": 1646237089,
    "direct_buy_tokens": {}
  1. Use the access token as a bearer token to make FreshBooks API calls on behalf of the user by including an ‘Authorization’ header in your API calls with the format Authorization : Bearer <YOUR_ACCESS_TOKEN>
  1. You can continue to keep making API calls with the access token until it expires. When the access token expires and you make an API call, you will get an http error status 401 unauthorized. This means that you need a new access token.
  1. To get a new access token, you will use the refresh token you stored earlier and request for a new pair of access & refresh tokens. This step is similar to the 4th step, the main difference here is that the grant_type is set to refresh_token and the key ‘code’ is replaced with the refresh token.
curl -L -X POST 'https://api.freshbooks.com/auth/oauth/token' \
-F 'grant_type="refresh_token"' \
-F 'client_id="943f08ec5a5797f579e2682103868216f2d00a64faf0fb36e8257c8acceebfc6"' \
-F 'client_secret="<APP_CLIENT_SECRET>"' \
-F 'refresh_token="f8cddb919402989a72918f55a8fe31f36f353d409e018781d0f59c44e1e59e03"' \
-F 'redirect_uri="https://b425-143-178-154-232.ngrok.io/settings"'
  1. As you see in the response below, you now have a new pair of access & refresh tokens. Replace the previous refresh token with the new one you just received and continue making API calls with the new access token.
    "access_token": "eyJraWQiOiJhMTlPSlR5aVlKOXhPM3FoWnhWeE1KZE5ZNXJ4cUhpQzBSTUY0TWRheGtjIiwiYWxnnRsQQPFVR7TMQp9chBYe2C_xKCcWorSC9GPVr4V_kc9NJGg",
    "token_type": "Bearer",
    "expires_in": 43199,
    "refresh_token": "0ba22fec6606365569638d8d82ff99f689746e866c75fa3ff4ae55f10aac2930",
    "scope": "user:profile:read user:expenses:read user:expenses:write user:clients:read user:clients:write",
    "created_at": 1646237284,
    "direct_buy_tokens": {}

Things to keep in mind

  • The authorization code is valid for only 5 minutes
  • An access token is valid for 12 hours
  • A refresh token can only be used once to get an access token. You must use the new refresh token next time
  • You don’t have to wait until an Unauthorized response; you can proactively request a new access token based on the expiry time provided. Requesting a new access token via a refresh token invalidates the previous access token immediately.

Ask us!

OAuth can get pretty complicated. If you’ve given this all a try and read as much documentation as you can find and you’re still running into problems, shoot us an email with information about what you’re doing, what you tried, and what went wrong, and we’ll do our best to help.

Good luck!