[Showcase] Manual OAuth2 Token Integration

Hey guys,

I struggled for a long time to get the OAuth2 working right. Eventhough I felt like I was making progress every day, different errors kept showing up every time, which drove me crazy (and that obviously didn’t help either :crazy_face: )

Thankfully I found a lot of help on this forum, especially @lottemint.md who very kindly offered his help and walked me through all the steps. I would probably never have succeeded without him! Big up to him and @NigelG for their understanding. I’m incredibly grateful for Bubble and the knowledge/help from its community, it shows once more that both together really make a huge difference!

Now that it’s working for me I want to give back to the community and help rookies like me understand how it should be done (I don’t have a huge tech background - I’m more that business kind of guy).

Below is a step-by-step guide - I’m taking the Hubspot example here but I guess it would work for other integrations that cannot be done with the User-Agent flow :

1. Create a Developer Account app on your integration

1.1 Build an app there:

1.2 Setup this app:

2. Setup your API calls using API Connector

2.1 Add an API with authentication ‘None or self-handled’

2.2 Setup the POST ‘Get Token’ call

  • You should be able to find the correct POST URL & Content-Type in the API documentation
  • Take the client_id, client_secret and redirect_uri from Step 1.2
  • Leave the ‘code’ parameter value blank for now

2.3 Setup the POST ‘Refresh Token’ call

  • You should be able to find the correct POST URL & Content-Type in the API documentation
  • Same client_id, client_secret and redirect_uri than above
  • Leave the ‘refresh_token’ parameter value blank for now

2.4 Setup the GET ‘Me’ call

  • You should be able to find the correct GET URL in the API documentation
  • Leave the ‘token’ parameter value blank for now

3. Build the first workflows

3.1 Create an ‘Auth’ page (one per integration)

That’s just a blank page with a centered simple loader (to insert a loader, I suggest using this plugin )

3.2 Go to the page from where the action begins (in my case, a clickable button called ‘Hubspot’ - let’s call it ‘Action Button’)

Create a Navigation workflow:

manual OAuth 3.2

  • Simply make the button redirect to your new ‘Auth’ page
  • Don’t forget to send the parameter ‘state’ = This URL

3.3 Go back to the ‘Auth’ page

Create an ‘Open an external website’ workflow (when Page URL doesn’t contain ‘code’)

manual OAuth 3.3.2

  • This is the OAuth URL from Step 1.2
  • Don’t forget to add the parameter ‘state’=Get state from page URL

3.4 Go back to the Action Button page and run it in preview mode

Click on the Action Button. At this point, the flow is Action Button (Bubble) -> Auth Page (Bubble) -> Login/Grant Access (Hubspot) -> Back to Auth Page (Bubble)

Copy the code from the URL when you get to the last step. It should look something like that:

Capture d’écran 2020-02-23 à 18.01.50

4. Initialize the calls

4.1 Initialize the POST ‘Get Token’ call

Paste the ‘code’ value from step 3.4 in the ‘code’ parameter value, and click on ‘Initialize’

You should get the returned values for access_token, refresh_token and expires_in.

  • Copy the ‘refresh_token’ value
  • Don’t forget to click ‘Save’

4.2 Initialize the POST ‘Refresh Token’ call

In the same way, paste the ‘refresh_token’ value from step 4.1 in the ‘refresh_token’ parameter value, and click on ‘Initialize’

You should once more get returned values as above.

  • Copy the ‘token’ value
  • Don’t forget to click ‘Save’

4.3. Initialize the ‘Me’ call

In the same way, paste the ‘token’ value from step 4.2 in the ‘token’ parameter value, and click on ‘Initialize’

  • Click ‘Save’

5. Build the next worklows

5.1 Create new fields in Data Type User

Create ‘hubspot_token’, ‘hubspot_refresh’ and ‘hubspot_refresh_scheduled’ as Text fields

5.2 Go back to the ‘Auth’ page

When calls are properly initialized, and we get that code in the ‘Auth’ page URL, we can automate the whole flow. Create a workflow when ‘code’ is not empty:

You’ll find initialized calls in the Add Action -> Plugins dropdown:

manual OAuth 5.2

You do not need to setup an endpoint for the following call:

5.3 Go to ‘Backend Workflows’

Create a new endpoint (in my case, I called it ‘hubspot_refresh’):

manual OAuth 5.3.2

5.4 Go back to the ‘Auth’ page

Add new actions to the workflow from step 5.2:

6. Set privacy rules

The ‘token’, ‘refresh_token’ and ‘hubspot_refresh_scheduled’ should be kept private from other users.

Go to Data -> Privacy and make sure you have these settings:

7. Done!

Run it with a Test User and make sure fields are properly populated for this user in Data -> App Data.

I hope this will be useful to current users and future ones (let’s face it, Bubble is amazing and attracts more and more users by the day) and please do let me know if I can help further or if you think something is wrong or missing.

All the best to all in all your projects! :beers:


What an excellent detailed article! Thanks for sharing it!

BTW, with a manual flow, you can allow admin users to execute actions on behalf of users. The Bubble’s OAuth2 flow doesn’t provide this possibility.

Also, the Bubble’s OAuth2 sometimes has issues with token refreshing. Here, you can configure it as you need. For instance, if a token expires in 21600 seconds, schedule the refresh token workflow in 21540 seconds.

This method you can use for other platforms as well. For instance, the Bubble’s OAuth2 doesn’t refresh tokens.


My pleasure, all the credit goes to you @lottemint.md :+1:

Good to know!


I don’t think it is entirely true though.

What this allows you to do is decouple the HubSpot Oauth token process from Bubble’s sign-up process. Which can be very useful particularly as Bubble does not refresh tokens for you.

I would also mention that some providers won’t be happy with you refreshing tokens every 6 hours without using them. The alternative is to check expiry before doing the calls and refresh at that point.

Other providers won’t let you refresh after a certain time after expiry so using the workflow is a the way to go.

You need to understand your providers policy :grin:


Yes, that’s right. It depends on things.
This method is a kind of template. Therefore, a developer may adjust it by the things you described.
If a token is expired, it will take a delay of ~2 seconds to update it in the workflow. So, not a good UX. Also, there may be an issue is a user has triggered some actions (tied to the same integration) using two devices or two tabs with a small delay. In that case, the system makes two requests.

You can cancel the refresh token logic if a user isn’t active - and then reschedule it when it gets back to the app.

1 Like

Great work, thanks guys.

Oauth2 can be a real pain, so thanks a lot for helping all of us to figure this out so clearly.


I just wanted my first post ever in the forums to be… THANK YOU! I followed this exactly, and it really strengthened our project. No just for Oauth2, but in general, we replicated this type of callback structure for other things. Thank you @ambroisedlg!!

Now, if I can just figure out how to make a --data-binary call with the API Connector, my whole life would be unicorns and rainbows.


Thanks for sharing. I was starting to worry that even Oauth was too complicated for me. Love the forum!!!


Hi, sorry if this is a stupid question but I can’t replicate the 'When" criteria - is this simply because Bubble.io has changed wording/synax?

I’ve attached your screenshot vs mine…

Hey @jeremyjameslevy

Click on ‘Get data from page URL’, and just write ‘code’ and ‘state’ as parameter names. Easy as that! :slight_smile:


Need extra help?

Book a free 15 minutes call - happy to help if I can

1 Like

Hey @ambroisedlg thanks so much for your reply.

I do actually have quite a few questions :rofl:

I’ve done quite a bit of visual coding through salesforce and love how Bubble opens up use cases on the entire web vs a single platform.

I’m very new to Bubble but have always found I learn best by doing (at least to start with). I’m trying to build a connection with Withings to pull my steps & weights into Bubble.

I wasn’t sure for instance if the JSON string in the API calls would be the same format as your Hubspot example.


Oh, also does that url:trimmed mean something?

@jeremyjameslevy the methodology is the same, but parameters differ from integration to integration.
The call you want to setup to get the token is this one: https://developer.withings.com/oauth2/#operation/oauth2-authorize
You need to include the required parameters from that doc in your API call. You can copy/paste the pre-made example on the right of the page and replace the values by your client_id, code, etc

:trimmed means you’re removing all the space from the code you get in the URL, it’s recommended but not always necessary

Hope this helps!

Need extra help?

Book a free 15 minutes call - happy to help if I can

1 Like

@ambroisedlg thank you, very helpful - that definitely helps. I’ve actually booked in 15 mins for us to chat this week to talk through this project & my overall goals & aims with Bubble. :ok_hand:

You’re welcome @jeremyjameslevy and looking forward to our call!


Need extra help?

Book a free 15 minutes call - happy to help if I can

Thansk for posting this, @ambroisedlg - you rock, man! :metal:

If I may, I’d just add one tiny clarification that could come in handy and possibly save hours of headache to someone out there. The reason why “Private” checkbox is left unchecked next to certain key-value pairs in the API Connector in the screenshots is because that’s the only way to use dynamic data in those API calls later in the app. If you check “Private”, Bubble will be using whatever hardcoded value you have in the API Connector; if you uncheck it, you will be able to pass the API dynamic values elsewhere in your app later.


Hey @ambroisedlg QQ: where did you get your url (https://developer.withings.com/oauth2/#operation/oauth2-authorize) from?

As it looks like in the documentation that they refer to this for url to get the authentication code?

I’m sure you’re right, I just don’t understand :confused:

hey @jeremyjameslevy

That’s the URL you need to redirect the user to to begin the login process. You’re then redirected to your app with an authorization code (step 3.3 of the above tutorial).

This is the URL to show you where you can find your different API calls in Withing’s documentation (including the above URL) - it’s not the URL you need to use to make your API calls


Need extra help?

Book a free 15 minutes call - happy to help if I can

Thanks @ambroisedlg - I’m beginning by trying to get the authentication code. When I initialise the call I get an error “Exceeded maxRedirects. Probably stuck in a redirect loop https://account.withings.com/oauth2_user/connectionuser” - Is this because I need a user to approve my app to have access as part of the workflow?


Once again, this URL (https://account.withings.com/oauth2_user/authorize2) is not for an API call.
It’s the URL you need to redirect the user for him to login (see Step 3.3 of the tutorial above)


Need extra help?

Book a free 15 minutes call - happy to help if I can