Accessing REST API with Google OAuth

Beginner here.

My organization’s instance of Metabase uses Google OAuth for signin. I want to figure out how I can send API calls to it and set it up so it automatically grabs a refreshed Google Auth token.

How would I go about this? Would I need my IT department to set up a Google API Service Account? If they do that, what would I do next?

Any documentation would be helpful.

-Michael

Hi @michaelkleban
Unless you’re hard set on using Google Auth, then you could just setup a regular non-Google user in Metabase, which uses email+password and that could be used for the API.
Also have a look at this topic: Metabase API Authentication

Thanks, Flamber. I will ask my security team if that’s possible. In case they require OAuth, do you know of any online resources you could point me to?

@michaelkleban You would need to do the authentication with /api/session/google_auth, which will return a session token that you’ll use in the header X-Metabase-Session. But I don’t know if you can do that programmatically with all the new much stricter cookie restrictions and Google’s protective measures.
If you check your browser developer console, then you can see every request send/received - almost everything you can do in the interface is also available in the API.

Alternatively, you can define an environment variable MB_API_KEY and pass the header X-Metabase-Apikey with the same value (I don’t remember testing this, so just writing from memory):
https://github.com/metabase/metabase/blob/6f271dbe7ec7598b6878dcdede88ffdfc68dcaac/docs/operations-guide/environment-variables.md#mb_api_key

EDIT: For reference: https://github.com/metabase/metabase/issues/13026

@flamber - I seemed to have figured out how to obtain a refreshed Google OAuth token. When observing the Network tab of Chrome Dev Tools upon signing into Metabase, there is a call it makes to Google called “iframerpc?action=IssueToken…”. Simply copy the headers and url endpoint from that and it seems to work each time. The “id_token” element from that JSON response is your refreshed token. That can then be used in the api/session/google_auth call you mentioned.

1 Like

@michaelkleban - I’m new at python and API’s. Could you help me ? (my english is not great)
I took the id_token and put at the token variable. Then, i tried to use the api/session/google_auth and I got an 404 error.
After I took the id_token, i did…

url_auth = ‘https://metabase.kovi.us/api/session/google_auth’

params_auth = {‘token’ : token}

r_auth = requests.post(url_auth, params = params_auth)

print(r_auth.status_code)

Hi @edchlee,

I apologize for the delayed response. Are you still having trouble with this?

Thanks,
Michael

Hi @michaelkleban,

No problem, I’m still having trouble,

Could u help?

Thanks,
eduardo

@edchlee - Try following these steps:

  1. Navigate to Metabase in Chrome
  2. Log out of Metabase if you are not logged out already
  3. Open the Developer window (or right click and select “inspect”)
  4. In the Developer window, go to the Network tab
  5. You will see a red record button in the upper left. Click that twice to reset the request tracking.
  6. Log into Metabase using Google Authentication
  7. Look for a request in the Network tab that starts with “iframerpc?action”. Click on that.
  8. Under “Headers” you will see several sections
    a.) General - Copy the Request URL from this section
    b.) Request Headers - Copy all of the elements from this section
  9. Make an API call to get the Session ID
    a.) URL = Request URL from the General section
    b.) Headers = Elements from the Request Headers section (if using Python , create and use dictionary of these items)
  10. The Response from the API call will include an element called “id_token”. This is your Session ID.
    NOTE: I personally did not have to include a payload in this particular API call

IMPORTANT : Keep in mind, that OAuth is meant to expire after a while (could be minutes, could a one or two days). The elements you copy and paste into your api call will eventually stop working, and you will have to repeat this process. I believe the element that changes is the “cookie” in the Request Headers

1 Like

@michaelkleban

Hello, out of curiosity, is there an updated / more streamlined way to getting the id token / session ID through the google auth route? I've been trying to debug this for the past couple hours, and have stumbled upon this thread, which seems to be the same issue I'm having.

For some more context, I'm simply following the guide on how to access the Metabase API with Python and I'm already hitting a roadblock after step 1:

response = requests.post(url='<remote-server-address>/api/session', 
                        json = {'username':'<my-email>',
                                'password':'<my-password>')}
                       )

The response object is giving me a 200 response code, but when I try to access the JSON with response.json() I'm getting thrown a decode error. Upon further inspection, it looks like it's because I'm not getting back a JSON after all, but rather the HTML for some additional sign-in page via CloudFlare.

I've tried adding the /google_auth to the url endpoint, and even tried the step-by-step guide you posted last (it's possible I didn't create the dictionary in the correct format) and still no JSON response. To be fair, maybe I didn't format the dictionary correctly (not sure exactly what you mean by "create and use a dictionary of these items"), but either way it seems like that way would be too manual / tedious anyways.

I'm not sure if my issue has to do with google authentication at all (I am also able to log in to our Metabase server using regular email and password without using the Google route at all) or if I'm just missing something really obvious.

In any case, thanks in advance for any help you can provide me. We're using Metabase now for our analytics and I'm really curious into seeing what kinds of useful things we can extract from the API, once I can manage to access it.

@alarmingboots If you are getting a HTML response back from that endpoint, then it's not coming from Metabase.
So without understanding your full setup, then it's difficult to know. Reverse-proxies can be your best friend, when they work, and the worst enemy at any other time.

Hello @flamber thank you for your super quick response!

I see, well it's at least useful to know that it's not coming from Metabase, but rather related to some third party. As someone who knows very little about networking (much less reverse proxies or how my company's IT system is set up), I would guess that this is something to do with the server that is hosting our Metabase app, i.e. the part of the url that precedes the /api/session? Perhaps it has some extra layer of security that I can somehow configure (potentially within the Admin panel of the Metabase app)?

It looks like I'll have to chat with some people in my company to get a better idea of how it all works, but would you by any chance have any idea/ hints as to what I should look into? I know you don't know my setup at all, but perhaps you've ran into similar things in your experience and might be able to at least point me in the right direction? Thanks again for your help!

@alarmingboots A reverse-proxy comes before the application (in this case Metabase), so there's nothing that Metabase can do about that. You have to change settings on your reverse-proxy.
Similar if you had a firewall blocking all ports, it also comes before the application, so there's nothing the application can do about that.

A simple example. Remove Metabase and just add a plain index.html, which will behave exactly the same, when there's a reverse-proxy doing "magic" in front (might require config changes on the proxy for that to even function).

It is close to impossible for anyone outside your company to help, since we have zero knowledge about your networking or security. You'll need to talk to someone inside of your company.

@flamber Thanks for the answer! Make sense. I've chatted to people within my company who can look into this, so I'm all good with this for now!