Skip to main content

Onboard Standard accounts

A Quaderno Connect Standard account is a conventional Quaderno account directly controlled by the account holder (i.e., your platform’s user).

Users with a Standard account have a direct relationship with Quaderno, are able to log in to their dashboard, can manage their Quaderno account on their own, and can disconnect their account from your platform.

You can prompt your users to create Quaderno accounts or allow anyone with an existing Quaderno account to connect to your platform.

How the process looks like

This is how the authentication process will look like for your users:

  1. They land on your site and start the connection process with Quaderno clicking on a Connect link or button.
  2. Users will be headed to a Quaderno site and asked for permission to access their Quaderno accounts. They can allow or deny the connection.
  3. Upon acceptance, they are redirected back to your site, and they can start using Quaderno functionalities to calculate taxes, issue invoices, and more. As easy as that!

This process is based on OAuth, a secure industry standard authorization system. Our OAuth flow allows you to securely obtain an access token for a Quaderno account without having to have your user’s password or do any manual setup.

There are three key benefits to getting access to your users’ accounts using OAuth:

  • It’s secure: Your users have a secure way to grant you access to their account without needing to send you their login credentials or an access token. They only need to tell us that you may have access through a simple online process.
  • It’s fast: You only need to generate and send your user to a link to our OAuth flow. From there, they’ll create a Quaderno account or sign in to their existing one, approve your access to their account, and then we’ll send them right back to you with an access token.
  • It’s future-proof: As the Quaderno API gets better and better over time and offers new functionality, you’ll be able to stay up-to-date and use all the latest features

OAuth flow to integrate Standard accounts

info

We encourage testing these steps on our sandbox environment first.

1. Creating an app

Before we can get started, you need to create an "app" which represents your platform in the Quaderno system.

  • You’ll be issued with a client ID and secret, which you’ll use to identify yourself when sending users to the OAuth flow and swapping codes for access tokens.
  • You’ll need to provide a name and the URL of your website, where users can read more about your product or integration with Quaderno.
  • A Callback URL endpoint must be publicly available on your servers. It will be used to fetch the authorization code from the OAuth process, providing the user accepts the app connection.

Once you’ve created an app that represents the integration of your platform into our system, you’ll see it in the list of your apps. Click on your newly-created app, and take note of the Client ID and Client Secret.

With these two pieces of information in hand (Client_ID and Callback_URL), you’re ready to create an OAuth link to be shown to your users as a link or button.

We provide your custom OAuth link for you in your list of apps. Note the default scope there is read_only. You would need to change it to read_write in case you need to create Transactions on behalf of your merchants.

This is how an OAuth link looks like:
https://quadernoapp.com/oauth/authorize
?redirect_uri={{CALLBACK_URL}}
&client_id={{CLIENT_ID}}
&response_type=code
&scope=read_write
&state={{OPTIONAL_CSRF_TOKEN}}

When clicked by the user, it will show a Quaderno website on their browser, prompting the user to allow or deny the connection. Afterwards they'll be redirected back to your application using the Callback _URL you provided with the redirect_uri parameter.

The OAuth2 Quaderno /authorize endpoint can receive these parameters:

| Param | Description | Required | --- | --- | --- | | client_id | Your app's client ID | ✓ | | redirect_uri | The URL to send your users to, once they've agreed to connect their account to Quaderno. In case they deny authorization or something goes wrong, we'll redirect and include details of the errors. Please make sure the string is URL Encoded. | ✓ | | response_type | Using code will redirect the user who followed the link to a prompt from our Oauth2 server, asking them to allow or deny the connection, and will get you a fresh short-lived temporal code for completing the OAuth connection (see steps 3 and 4). | ✓ | | scope | The level of access you want to your users' Quaderno accounts - this may either be read_write or read_only. Default is read_only. | | state | Any value you send here will be included as a querystring parameter when we redirect back to your redirect URL. We recommend using this parameter for a CSRF token. Please note that this value can be tampered with by your user, so it shouldn't be trusted implicitly. | | utm_source | Optional parameter to use in case you're registered in Quaderno's Affiliates Program. |

tip

In your application, you might want to consider using a dedicated OAuth client library to simplify these steps. To find an OAuth library for your language or framework, you can refer to the list of client libraries on the OAuth website.

Here is a Ruby code example for this step:

# This example uses oauth2 library, you may need to do this first:
# echo "gem 'oauth2'" >> Gemfile
# bundle install

require 'oauth2'

# You should store your client ID and secret in environment variables rather than committing them with your code
oauth = OAuth2::Client.new(ENV['QUADERNO_CLIENT_ID'],
ENV['QUADERNO_CLIENT_SECRET'],
site: 'https://sandbox-quadernoapp.com',
authorize_url: '/oauth/authorize',
token_url: '/oauth/token')

authorize_url = oauth.auth_code.authorize_url(redirect_uri: 'https://yourapp.com/redirect',
scope: 'read_only')

redirect_to authorize_url

3. Obtaining user's temporal authorization code

After the user clicks the link on your site, they'll be taken to Quaderno's website where they'll be prompted to allow or deny the connection to your platform.

The process of creating a Quaderno account is incorporated into our authorization flow. You don't need to worry about whether or not your users already have accounts.

After the user connects their existing or newly created Quaderno account to your platform, they are redirected back to your site using the Callback URL established as your platform’s redirect_uri.

For successful connections, we’ll include in the URL the following parameters to your callback endpoint:

  • The state value, if provided
  • A temporal authorization code. This code is short-lived and can be used only once in the POST request described in the next step.
Succesful callback with authorization code to obtain a permanent token:
{{APP_CALLBACK_URL}}?code=ca159b06d86757dbcae2e6950faf8fb2e9e7f596574a1df3f7294cf26a1f9e02

In case the authorization was denied by the user, they'll still be redirected back to your site, but the URL includes an error parameter instead of the authorization code.

OAuth denied by the user:
{{APP_CALLBACK_URL}}?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.

4. Obtaining OAuth permanent access tokens

The process of exchanging a code for an access token should be done on your server so your client secret can be kept private.

Include the provided authorization code in a POST request to Quaderno's /token endpoint to complete the connection and fetch the user’s account ID and the permanent tokens:

curl https://quadernoapp.com/oauth/token \
-u {{APP_CLIENT_ID}}:{{APP_SECRET_KEY}} \
-d code={{OAUTH_AUTHORIZATION_CODE}} \
-d redirect_uri={{APP_CALLBACK_URL}} \
-d grant_type=authorization_code

Quaderno will return a response that includes the account ID (account_id) for the user and the OAuth access tokens (access_token and refresh_token):

{
"token_type": "bearer",
"account_id": "{ACCOUNT_ID}", // needed for webhooks
"refresh_token": "{REFRESH_TOKEN}", // does not expires
"access_token": "{ACCESS_TOKEN}" // expires on 25 days for Standard accounts
...
}

Store your users' access_token and refresh_token safely in your database, as they give full access to your user’s Quaderno account.

Checkout a Ruby code example for this step:

require 'oauth2'

oauth = OAuth2::Client.new(ENV['QUADERNO_CLIENT_ID'],
ENV['QUADERNO_CLIENT_SECRET'],
site: 'https://sandbox-quadernoapp.com',
authorize_url: '/oauth/authorize',
token_url: '/oauth/token')

response = oauth.auth_code.get_token(
params[:code], # temporal access token from step 3
redirect_uri: 'https://yourapp.com/redirect'
)

# You should store the user's access token as you'll need it to make API requests on their
# behalf. In case you want to handle webhooks for your users, you should also store
# their account ID which will allow you to identify webhooks belonging to them.
current_user.update!(quaderno_access_token: response.token,
quaderno_account_id: response['account_id'])

Common problems

Common problems are not including the exact URL encoded redirect_uri (you can grab the exact string on the Quaderno app listing), or using expired codes.

In these cases, you'll get a 401 Unauthorized with a mesage like:

{ "error": "invalid_grant", "error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." }

If that happens, you may need to repeat the whole OAuth process.

That's it! 🎉 Congratulations, the integration is completed and you can now act on your user's behalf.

Making API calls on behalf of your users

To make API calls on behalf of your connected accounts, use an Authorization: Bearer {{access_token}} header per API request, either Standard or Custom accounts.

Calculating taxes on behalf of a connected account:
curl https://quadernoapp.com/api/tax_rates/calculate?to_country=US&to_postal_code=90210&tax_code=eservice \
-H "Authorization: Bearer {{access_token}}"

Refreshing tokens

Eventually you will need to refresh the tokens for security reasons.

info

To ensure the highest level of security, access_token expires every 25 days, as informed in the expires_in response parameter. Your integration is responsible of refreshing tokens.

Use the refresh_token to get fresh access tokens. Note that refresh tokens does not expire.

Example for refreshing your token, using grant_type=refresh_token:

curl https://quadernoapp.com/oauth/token \
-u {{APP_CLIENT_ID}}:{{APP_SECRET_KEY}} \
-d refresh_token={{YOUR_REFRESH_TOKEN}} \
-d grant_type=refresh_token

Revoking access

To disconnect a Standard account, POST your client_id, your client_token, and the user's access_token to the API endpoint /oauth/revoke:

curl https://quadernoapp.com/oauth/revoke \
-d client_id={{APP_CLIENT_ID}} \
-d client_secret={{APP_CLIENT_SECRET}} \
-d token={{ACCESS_TOKEN}} \

Revoking a token successfully will return an empty body response with 200 OK status code.

Self-hosted software

When your platform operates as a plugin for WordPress or other self-hosted software out of your full control, you may not be able to implement the OAuth authentication shown above.

For these exceptional cases, we allow you to request the user's private API Keys in your UI, so that your plugin can make API calls on the Standard account's behalf that way.

danger

Using API keys directly is strongly discouraged for security reasons. Leaked API keys could potentially cause serious issues, as private API keys grant broad permissions including the ability to read and write sensitive data and move money.

Most Connect platforms should avoid using API keys and instead use the OAuth authorization flow shown above.

For those reasons, always protect API keys. They should remain internal to your systems and never be accessible from browsers or API endpoints.