How can I use the Google API in a chrome extension?
Asked Answered
C

2

8

I'm now searching for hours how I can use the Google API in a chrome extension. All I want to do is to parse the contents of a website and insert it as a new event to Google Calender. I got the parsing and everything, but it seems to be impossible to use the Google API inside a Chrome extension. I'm just trying to write an example event when clicking the button in my chrome extension, but it keeps refusing to load the Google API with this error:

Refused to load the script 'https://apis.google.com/js/platform.js' because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

My manifest.json:

{
    "manifest_version": 2,

    "name": "DVB2Calender",
    "description": "This extension will export the current viewed schedule to your Google Calender.",
    "version": "1.0",

    "content_security_policy": "script-src 'self' https://apis.google.com/; object-src 'self'",

    "browser_action": {
     "default_icon": "icon.png",
     "default_popup": "popup.html"
    },
    "permissions": [
     "activeTab"
     ]
}

My popup.html

<!doctype html>
<html>
  <head>
    <title>DVB2Calender</title>
    <meta http-equiv="Content-Security-Policy" content="default-src *;">
    <script src="popup.js"></script>
    <script src="https://apis.google.com/js/platform.js" async defer>
    </script>
  </head>
  <body>

    <h1>DVB to Calender</h1>
    <button id="exportToCalender">Export this calender to Google Calender!</button>

  </body>
</html>

My popup.js:

document.addEventListener('DOMContentLoaded', function() {
    var checkPageButton = document.getElementById('exportToCalender');
    checkPageButton.addEventListener('click', function() {

        chrome.tabs.getSelected(null, function(tab) {
            var head = document.getElementsByTagName('head')[0];
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = "https://apis.google.com/js/client.js?onload=callbackFunction";
            head.appendChild(script);

            d = document;
            var download = d.getElementsByClassName('icon-link ico-calender')[6];
            var request = makeHttpObject();
            request.open("GET", download, true);
            request.send(null);
            request.onreadystatechange = function() {
                if (request.readyState === 4) {
                    var resultText = request.responseText;
                    array = CSVToArray(resultText, ":");
                    alert(resultText);

                    var resource = {
                        "summary": "Appointment",
                        "location": "Somewhere",
                        "start": {
                        "dateTime": "2011-12-16T10:00:00.000-07:00"
                        },
                        "end": {
                        "dateTime": "2011-12-16T10:25:00.000-07:00"
                        }
                    };
                    var request = gapi.client.calendar.events.insert({
                    'calendarId': 'primary',
                    'resource': resource
                    });
                    request.execute(function(resp) {
                    console.log(resp);
                    });
                }
            };
        }
    }
}
Cq answered 1/5, 2019 at 10:56 Comment(2)
Not sure if it would make any difference, but try changing https://apis.google.com/ by https://apis.google.com (without the last slash) in the content_security_policy. In the examples I've found, the last slash is never used. Also, all the code in your popup.js file (including the chrome.tabs.getSelected listener) runs in the popup: you probably need a content script for your purposeDawna
I will try that! I think there also an issue with the reload as mentioned in the answer from Michal. I spent lots of hours trying to get it to work with a content script yesterday, but eventually gave up, I will give this another shot today.Cq
I
4

I have made a chrome extension using reactJS, making use of Google Calendar API for creating calendar events. I have pasted the link below, hope that it might help people to get an idea of how to implement the above use case properly.

Project Link (Do star the repo, If this helps you)

For using google calendars API, a pre requisite is to configure Oauth2 first because Google Calendar Api requires auth token. Your manifest file must contain changes to configure OAuth.

After configuring Oauth2 inside the manifest file of chrome extension, the following function will help you make a call to create an event.

function createMeeting() {
  chrome.identity.getAuthToken({ interactive: true }, function (token) {
    console.log(token);

    
    //details about the event
    let event = {
      summary: 'Google Api Implementation',
      description: 'Create an event using chrome Extension',
      start: {
        'dateTime': '2015-05-28T09:00:00-07:00',
        'timeZone': 'America/Los_Angeles'
      },
      end: {
        'dateTime': '2015-05-28T09:00:00-07:00',
        'timeZone': 'America/Los_Angeles'
      }
    };

    let fetch_options = {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(event),
    };

    fetch(
      'https://www.googleapis.com/calendar/v3/calendars/primary/events',
      fetch_options
    )
      .then((response) => response.json()) // Transform the data into json
      .then(function (data) {
        console.log(data);//contains the response of the created event
      });
  });
}

Make sure your manifest file has the following entries:

"oauth2": {
    "client_id": "your id",
    "scopes": [
      "profile email",
      "https://www.googleapis.com/auth/calendar",
      "https://www.googleapis.com/auth/calendar.readonly"
    ]
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
  "permissions": [
      "identity",
      "identity.email"
    ]

To breakdown:

  1. For using Google API in chrome extension, first thing you need to do is to log-in. As so many "security restriction" nowadays, you can't import the that API js like a website anymore. Instead, you need to use the browser api to grant the access, a.k.a. chrome.identity.getAuthToken (https://developer.chrome.com/docs/extensions/reference/identity/#method-getAuthToken). But to get this browser api works, you still need to do bunch of other works, e.g. manifest, packing extension, etc. But you can learn those things and why those are related with Google by searching this browser api.

  2. After STEP 1 success, you will get a token with chrome.identity.getAuthToken. Now you need to know what to do to request Google APIs with this token. Like the example in this page (https://developers.google.com/streetview/publish/first-app), we can see the token can be sent in header like this authorization: Bearer YOUR_ACCESS_TOKEN. So now we know we can use fetch / XMLHttpRequest with this header to get the Google API works for the user.

Isocyanide answered 26/10, 2020 at 6:52 Comment(5)
While this link may answer the question, it is best to include the essential parts of the answer here and provide the link for reference. A code example can be very useful. Link-only responses may become invalid if the linked page changes.Atticism
@borchvm Thank you for your suggestion. I have worked on your suggestion and did the required changes.Isocyanide
This will give you limited control on auth flow. User will ONLY be able to select Chrome user account and not any google account.News
In fact, if you somehow find a way to "get" the google account id (mine is a 21-digit integer), you can use platform.identity.getAuthToken({account: { id: _21_DIGIT_GOOGLE_ID_, ... }, ...) to login an account even not logged in in browser.Artisan
What happens if the chrome profile you're logged in with does not match the actual user logged in with the browser? Will it still work or is it bound to the Chrome profile?Arbitrament
N
1

It looks like you just forgot to reload extension package. Note, that every time change is made to the extension code, reload which can be done here chrome://extensions/ is necessary to code changes take effect.

chrome extension package reload

To check if the client script is ready to be used, it is suggested to add onload callback like this:

window.callbackFunction = function(){
  alert('client.js ready')
  // here goes google client api calls
}

Name of the onload callback function is specified by onload parameter in script url.

Nicias answered 2/5, 2019 at 8:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.