OAuth with Google APIs - API Connector

Hello Folks,

I’m trying to integrate a Google API (Prediction API) using the API Connector and having some difficulty around authentication. The Google API requires OAuth; however, the nature of the API call is not necessarily against personally owned data, and therefore Google allows for both personal accounts, alongside Service accounts, to be used to authenticate.

Per Google’s instructions, I’ve used the Google Cloud Platform console to create an OAuth “Other” (service account) credential type, where Google provides both a Client ID and Client Secret. I’ve also used the Google OAuth Playground to authenticate against the API and test my API calls (everything worked fine). I also used a generated access token in an API call from Apigee (web based API client) to test my calls from there - everything again checked out.

My problem arose when trying to make the call from the Bubble API Connector. When I attempt to Initialize the API Connector, it returns an authentication error. Within the API Connector, I’ve selected the following:

I then filled out the rest of the call with a “Post” to the proper API endpoint, header for content-type, JSON body, etc. As I mentioned, the contents of the call should be good as I’ve tested it from two other locations successfully using an already generated access token.

Where is this potentially going wrong? Is the Username / Password section being appropriately used with the Client ID and Client Secret? Also, Google provides two separate URLs: “Authorization Endpoint” (https://accounts.google.com/o/oauth2/v2/auth) and “Token Endpoint” (https://www.googleapis.com/oauth2/v4/token). The former, I assume, is for the exchange of a Client ID/Secret for an Authorization token, and the latter, I assume, is to exchange that Authorization token for an Access Token that can be then used with an "Authorization: Bearer " header? Bubble, however, only appears to take one URL parameter (Token Endpoint).

Any help here is much appreciated. I assume this works the same across various Google APIs on their Cloud Platform, so hopefully some of you may have figured this out. Thank you!

Yes, I looked at that recently and was similarly confused.

You don’t send user/password to either of those Google endpoints so I am not quite sure what it is for.

As you have (I think) rightly said, you use /auth with your client id/scope to ask the user to authenticate externally, which then returns you to a redirect page with the auth code in the # fragment of the URL.

Extract the auth code from the URL, and then go to /token with your secret and you will get the bearer token back. You can then use that bearer token to call the API.

But that /auth is server side, you don’t want to be exposing the client secret in the client.

I don’t know it that is how the Prediction API works, but that is how it works with YouTube. And I have really struggled to get it to work in Bubble, even with a major amount of hacking with external bits of code.

Thanks for the response Nigel.

The scenario I’m going after is a little different than the conventional 3-leg OAuth protocol. In my case, I want my Bubble app to be the “client” to the Google API - more of a 2-leg OAuth with just a client-server flow. The end user of the Bubble app, in my case, wouldn’t have credentials against Google (or ownership of this specific data), so it’s not the traditional delegation of authority found in the 3-leg OAuth model.

I was hoping to avoid OAuth altogether as it seems like overkill for a pure client-server scenario. Even though the Google documentation suggests that a traditional “API Key” (passed as a parameter) is a valid alternative (even suggesting it may be easier if delegated authority isn’t a concern), I can’t get it to work. There appears to be conflicting documentation suggesting that OAuth is the only mechanism, and potentially JWTs.

I think in the scenario you’re describing (3-leg), you may be right - you originally only pass the Client ID and scopes. In fact, if you create an OAuth credential in Google and say it’s for use with a Web app, you only receive a Client ID (no Client Secret). If I say the OAuth credential is for use in an “Other” type of app (presumably not web, and where perhaps a web redirect isn’t possible), it provides both a Client ID and Client Secret.

I probably have more research to do here. But I was hoping someone might have (a) gotten a basic OAuth flow to work with the API Connector and could share how, or (b) experience with client-server API usage against Google’s APIs.

Yes, I think that is server-to-server flow ? Looks like you need either to use the Google API or encode your own JWT !!

As there is nowhere to set up your credentials in Bubble API connector (id and secret) it doesn’t look very oauth2 friendly. Unless you can just encode the thing anyway and send it on the header ?

The API connector doesn’t support user-agent flow yet, and Google doesn’t support the password flow

2 Likes

@NigelG and @emmanuel - thanks for the replies.

Doesn’t sound promising? I spent a lot more time reading the Google documentation, and the only flow that explicitly sounds like it’s intended to work with Server-to-Server (no end user consent) is their Service Account credentials. Looking through the documentation, they supply both Java and Python examples (using their SDK), but they also show pure HTTP interaction.

Essentially, it requires:

  1. Build a JWT

  2. Send the JWT to the OAuth2 token endpoint (skipping the Authorization token step of typical 3-leg OAuth), and receiving a bearer token.

  3. Creating the API request with the typical embedded "Authorization: Bearer " header.

Building the JWT is clearly the problem here on Bubble. The build-up seems doable (it’s just JSON-formatted data), but it then needs to be Base64URL-safe encoded (not sure there’s a way to do that here?) and then digitally signed using the Service Account’s X.509 certificate (REALLY don’t believe there’s a way to do that here!).

Beyond that point, I imagine steps 2 and 3 are very possible with the OOTB API Connector, assuming it’s just a matter of parsing the Bearer token from the JSON response of Step 1 and passing along to Step 2.

Emmanual - any thoughts on whether it’s remotely possible to create a JWT in Bubble? If not, I’d be interested in discussing what it looks like to sponsor this feature.

Thanks,
Eric

1 Like

You can download a JSON Public Web key in the API section of the Settings Tab, but I’m not sure that’s what you’re looking for.

@emmanuel - No, not what I’m looking for here. The way I see it, if Google’s OAuth2 server doesn’t support the Password flow (your link above and what it looks like Bubble has implemented support for in the API Connector?), then the only other way would be to attempt to use the Service Account support they provide. That requires building up a JSON Web Token from a set of credentials they supply you (upon creating a Service Account in their console). The credentials can be downloaded as a simple JSON file (containing a client_id, x-509 cert, etc) or an old school P12 formatted file.

Here’s how they instruct to do this:

Google API OAuth2 Service Account

1 Like

So it’s not somethings we support, as I was afraid. We’ll look at standard oauth2 first and need to see how we can do this, so we won’t be able to do this in the very near future.

@emmanuel - thanks… I figured it may be a lost cause there.

It’s not ideal, but it does look like there may be services that I can call externally to create a JWT. It’s just awfully time consuming (both in development, for me, and I’m afraid at run-time for a user!) to have so many orchestrated steps… all just to call an API. :slight_smile:

But I’m going to give it a shot, even just as a proof of concept - hoping something productized within Bubble will come along to take its place. As I said, I’d be interested in sponsoring the development if it helps expedite a solution.

I’ll post an update here after I’ve tried playing with some work-arounds.

1 Like

That is why I ended up with webtask.io and some node to do something similar. But it is time consuming I agree.

Be very interested to hear about how you got on.

Hi there,
What external service @ezmaass are you using?
@NigelG did you have your own server controlled by you on a heroku instance for example and generate the JWT and then pass it to Bubble.is?

Thanks for your time.
SDK

It was hosted on webtask.io which is node.js based.

You can use certain node modules, and it would seem like there are a few that will sign the JWT etc for you.

Thank you @NigelG Gotcha. Geoff at webtask.io pointed me to

var JWT = require(‘jsonwebtoken’);

module.exports = function (ctx, cb) {
// …
};

Yes, that looks familar.

So this is a little bit of node.js that takes a URL with a JWT as a hash and pulls out the

const url = require(‘url’);

module.exports = function(context, cb) {
cb(null, url.parse(context.query.qurl));
}

From this call…

https://webtask.it.auth0.com/api/run/wt-nigel_godfrey-gmail_com-0/parseurl?qurl=This url:formatted as URL encoded

Next task was to grab the JWT and decode. Still a WIP :slight_smile:

But basically…

context is the input … cb (= callback) is the output. So it takes the parameter qurl and does a url.parse on it returning the output in the response.

So maybe …

var JWT = require(‘jsonwebtoken’);

module.exports = function(context, cb) {
cb(null, jwt.sign({context.query.someinput}, “app secret”, { algorithm: ‘RS256’});
}

1 Like