google / google-api-javascript-client

Google APIs Client Library for browser JavaScript, aka gapi.
Apache License 2.0
3.22k stars 1.06k forks source link

Compatibility with Chrome's Manifest V3 extension platform #713

Open dotproto opened 3 years ago

dotproto commented 3 years ago

Devs, what features GAPI you're using an your extensions?

If you are an extension developer affected by this issue, please describe what GAPI capabilities you are using and what alternative approaches you've considered.

Issue description

Chrome is in the process of transitioning extension to a new platform we commonly refer to as Manifest Version 3 (MV3). This new platform introduces a number of changes to improve the security and privacy of extension users. One of the major changes coming to the platform is that extensions will no longer be allowed to run code retrieved from remote servers. In other words, extensions won't be able to fetch https://apis.google.com/js/api.js as described in the Getting Started guide.

On the Chrome extension team, we have been advising developers to package third-party libraries with their extensions in order to work around this limitation. I'm not personally familiar with the JS GAPI library, so I'd like to ask whether this guidance is appropriate for this library or whether we need to explore alternative approaches.

EDIT 2021-04-02: Grammar fixes. EDIT 2021-04-05: Added an intro section EDIT 2021-05-19: Chromium issue 1164452 is also related.

sergentj commented 3 years ago

Hi, no, it's not possible for third-party developers to bundle GAPI with their applications.

kospl commented 3 years ago

This is known bug, circa 2012: https://github.com/google/google-api-javascript-client/issues/586 https://github.com/google/google-api-javascript-client/issues/312 https://github.com/google/google-api-javascript-client/issues/261 https://github.com/google/google-api-javascript-client/issues/64

Arthur404 commented 3 years ago

https://www.google.com/recaptcha/api.js - here are the comments that this code DO NOT COPY AND PASTE. It's not possible to add a recaptcha to the extension Manifest V3 if don't allowed to add third party code

thdoan commented 3 years ago

I hope that GAPI and Extensions teams can agree on a vetted list of internal libraries that can be remotely hosted if a bundling solution does not come to fruition.

ccdunder commented 3 years ago

It looks like this is also being tracked in crbug here.

luciferpd13 commented 3 years ago

Hi @dotproto Any Update on this ? We need some solution for this. Also is Google thinking something for remote hosting code, we have to deploy our changes according to requirements and google review process is very slow. we can't deploy it to chrome web store again and again

Chrome is in the process of transitioning to extension developers to a new extension platform called Manifest Version 3 (MV3). ThisNew platform introduces a number of changes to improve the security and privacy of extension users. One of the major changes coming to the platform is that extensions will no longer be allowed to run code retrieved from remote servers. In other words, extensions won't be able to fetch and https://apis.google.com/js/api.js as described in the Getting Started guide.

On the Chrome extension team, we have been advising developers to package third-party libraries with their extensions in order to work around this limitation. I'm not personally familiar with the JS GAPI library, so I'd like to ask whether this guidance it's appropriate for this library or whether we need to explore alternative approaches.

thdoan commented 3 years ago

afaik GAPI isn't a framework that can be packaged into a local file.

On Thu, Apr 1, 2021, 5:30 AM Prasanna Dubey @.***> wrote:

Hi @dotproto https://github.com/dotproto Any Update on this ? We need some solution for this. Also is Google thinking something for remote hosting code, we have to deploy our changes according to requirements and google review process is very slow. we can't deploy it to chrome web store again and againg

Chrome is in the process of transitioning to extension developers to a new extension platform called Manifest Version 3 (MV3). ThisNew platform introduces a number of changes to improve the security and privacy of extension users. One of the major changes coming to the platform is that extensions will no longer be allowed to run code retrieved from remote servers. In other words, extensions won't be able to fetch and https://apis.google.com/js/api.js as described in the Getting Started https://github.com/google/google-api-javascript-client/blob/master/docs/start.md guide.

On the Chrome extension team, we have been advising developers to package third-party libraries with their extensions in order to work around this limitation. I'm not personally familiar with the JS GAPI library, so I'd like to ask whether this guidance it's appropriate for this library or whether we need to explore alternative approaches.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/google-api-javascript-client/issues/713#issuecomment-811873259, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7LRZ4JU6OF533GZAPXNMTTGRRPPANCNFSM4WAHPP6Q .

luciferpd13 commented 3 years ago

afaik GAPI isn't a framework that can be packaged into a local file. On Thu, Apr 1, 2021, 5:30 AM Prasanna Dubey @.***> wrote: Hi @dotproto https://github.com/dotproto Any Update on this ? We need some solution for this. Also is Google thinking something for remote hosting code, we have to deploy our changes according to requirements and google review process is very slow. we can't deploy it to chrome web store again and againg Chrome is in the process of transitioning to extension developers to a new extension platform called Manifest Version 3 (MV3). ThisNew platform introduces a number of changes to improve the security and privacy of extension users. One of the major changes coming to the platform is that extensions will no longer be allowed to run code retrieved from remote servers. In other words, extensions won't be able to fetch and https://apis.google.com/js/api.js as described in the Getting Started https://github.com/google/google-api-javascript-client/blob/master/docs/start.md guide. On the Chrome extension team, we have been advising developers to package third-party libraries with their extensions in order to work around this limitation. I'm not personally familiar with the JS GAPI library, so I'd like to ask whether this guidance it's appropriate for this library or whether we need to explore alternative approaches. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#713 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7LRZ4JU6OF533GZAPXNMTTGRRPPANCNFSM4WAHPP6Q .

So what's the solution ?

kospl commented 3 years ago

@thdoan whitelist is SO away from web standards, I don't think Google will like this idea

thdoan commented 3 years ago

I hope they come up with a solution that allows us to continue using GAPI in Chrome MV3 extensions.

On Fri, Apr 2, 2021, 2:32 AM Kostiantyn Plakhotia @.***> wrote:

@thdoan https://github.com/thdoan whitelist is SO away from web standards, I don't think Google will like this idea

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/google-api-javascript-client/issues/713#issuecomment-812452966, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7LRZ35EKWWDERRHUJV4TTTGWFLZANCNFSM4WAHPP6Q .

dotproto commented 3 years ago

@kospl, @Arthur404, @thdoan, @luciferpd13, what capabilities of the GAPI are you currently leveraging in your Manifest V2 extensions? What, if any, alternatives have you considered to using this library?

luciferpd13 commented 3 years ago

@dotproto This library doesnot support Google Location API's . Its very important.

luciferpd13 commented 3 years ago

Due to New CSP Policy. None alternatives are working

thdoan commented 3 years ago

@dotproto I'm using GAPI for Google Sheets integration; there is currently no GAPI replacement that I'm aware of. If Google is willing to provide a local GAPI library that we can download and package with our extensions, I'm all for it.

zamiang commented 3 years ago

Based on some earlier threads linked above, I have successfully made requests to Google APIs from MV3 extensions using the approach below. This is meaningfully less convenient that using gapi, but it does work 🤷‍♂️

In short, you log the user in with fetchToken() and then use that token to make further requests (see the tasks API example at the end).


/*
 * Create form to request access token from Google's OAuth 2.0 server.
 */
const oauth2SignIn = (additionalScope?: string) => {
  // NOTE: this needs to be a form: https://stackoverflow.com/questions/48925165/cors-issue-with-google-oauth2-for-server-side-webapps

  // Create element to open OAuth 2.0 endpoint in new window.
  const form = document.createElement('form');
  form.setAttribute('method', 'GET');
  form.setAttribute('action', oauth2Endpoint);
  const params = getParams();
  if (additionalScope) {
    params.scope = `${params.scope} ${additionalScope}`;
  }

  // Add form parameters as hidden input values.
  for (const p in params) {
    const input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }
  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  return form.submit();
};

// Parameters to pass to OAuth 2.0 endpoint (I recommend having these in some config file)
const getParams = () => ({
  client_id: config.GOOGLE_CLIENT_ID,
  redirect_uri: config.REDIRECT_URI,
  scope: config.GOOGLE_SCOPES.join(' '),
  state: window.location.pathname,
  include_granted_scopes: 'true',
  response_type: 'token',
});

const fetchToken = async () => {
  const params = getParams();
  // localStorage is used for convenience and speed and is not required
  const currentAccessToken = localStorage.getItem('oauth2');
  const currentScope = localStorage.getItem('scope');

  if (currentAccessToken) {
    // Test the auth token with an endpoint to make sure it is still valid
    const result = await fetchSelf(currentAccessToken); // use whatever works for you, this hits the /me people endpoint i think
    if (result.id) {
      return {
        accessToken: currentAccessToken,
        scope: currentScope || params.scope,
      };
    }
  }

  const fragmentString = location.hash.substring(1);

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  const urlParams: any = {};
  const regex = /([^&=]+)=([^&]*)/g;
  let m = null;
  while ((m = regex.exec(fragmentString))) {
    urlParams[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(urlParams).length > 0) {
    localStorage.setItem('oauth2', urlParams.access_token);
    localStorage.setItem('scope', urlParams.scope);
    window.location.hash = '';
    if (urlParams.state) {
      history.pushState('', 'Dashboard', urlParams.state);
    }
  } else {
    oauth2SignIn();
  }
  return {
    accessToken: urlParams.access_token,
    scope: urlParams.scope,
  };
};

// Example API request using the accessToken above
const taskResponse = await fetch(
  `https://tasks.googleapis.com/tasks/v1/lists/${taskListId}/tasks/${taskId}`,
  {
    method: 'PATCH',
    headers: {
      'Content-Type': 'application/json',
      authorization: `Bearer ${accessToken}`,
    },
    body: JSON.stringify(body),
  },
);
luciferpd13 commented 3 years ago

Every one not use Google login to sign in the user, there is also a manual login. MV3 requires some serious work here

zamiang commented 3 years ago

@luciferpd13 Quite sure I am using MV3 :) - the migration process was very memorable.

In the example scenario, I am not making these requests from service workers but from the popup. I also don't believe you can create and submit form elements from service workers - that is the more critical part in that example (local storage is easily worked around or not used).

@luciferpd13 In this case there is no manual login since the user is already logged into the chrome browser - you just get a token back from chrome.identity.getAuthToken and then pass that to your endpoints (as accessToken in the task example). My code is shared across a chrome extension and a webapp (as was originally possible with gapi), so I implemented a platform-agnostic auth solution.

luciferpd13 commented 3 years ago

@zamiang That's what I am saying every one don't use Google Login. Also I see you are just making an api calls using token but there's more to that in GAPI. I believe @dotproto might come with the solution

zamiang commented 3 years ago

My examples assume OAUTH2. But you are correct that GAPI also handles the 'simple' auth method that uses an API key (https://github.com/google/google-api-javascript-client/blob/master/docs/auth.md).

For the simple method, you would just put the API key in the url params of your GET request. For example, looking at these docs (https://developers.google.com/maps/documentation/javascript/get-api-key), you would make a http GET request to this endpoint -https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&key=YOUR_API_KEY&callback=initMap.

Are there other auth methods not covered by OAUTH2 or API keys?

luciferpd13 commented 3 years ago

@zamiang Already tried not working in manifest v3 due to CSP

luciferpd13 commented 3 years ago

Also we can't make every api calls in terms of url there are too many methods there ,that's why we are using Google scripts

zamiang commented 3 years ago

@luciferpd13 Just to clarify, so script-src 'self' prevents the extension from loading external script files. It does NOT prevent the extension from making external HTTP requests (that would be connect-src). The reason gapi does not work in a chrome extension, is because it is a script file hosted outside of the chrome extension, not because it makes http requests to google.

If you want to make AJAX requests from a chrome extension, you need to list those urls in host_permissions (https://developer.chrome.com/docs/extensions/mv3/match_patterns/ & https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/#host-permissions) in MV3 but I believe we are getting a bit off track and into debugging your specific issue with your MV3 manifest file as it is certainly possible to make AJAX requests from a MV3 chrome extension.

The issue is more usability (I miss having automatic typescript types personally) and do wish this package could be released in a similar way to how the typescript types are packaged. As mentioned above, it is still possible to build extensions in MV3 that use google apis, it is just a bit less fast and maintainable.

nielm commented 3 years ago

@kospl, @Arthur404, @thdoan, @luciferpd13, what capabilities of the GAPI are you currently leveraging in your Manifest V2 extensions? What, if any, alternatives have you considered to using this library?

I am using GAPI to call oauth-authenticated Google APIs from my MV2 background page in my extension. My extension makes these calls in the background so cannot use the pop-up or the foreground page as a context to execute the GAPI calls. I leverage the chrome.identity API to take care of all the OAuth flow...

Potential Workarounds for MV3?

luciferpd13 commented 3 years ago

@luciferpd13 Just to clarify, so script-src 'self' prevents the extension from loading external script files. It does NOT prevent the extension from making external HTTP requests (that would be connect-src). The reason gapi does not work in a chrome extension, is because it is a script file hosted outside of the chrome extension, not because it makes http requests to google.

If you want to make AJAX requests from a chrome extension, you need to list those urls in host_permissions (https://developer.chrome.com/docs/extensions/mv3/match_patterns/ & https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/#host-permissions) in MV3 but I believe we are getting a bit off track and into debugging your specific issue with your MV3 manifest file as it is certainly possible to make AJAX requests from a MV3 chrome extension.

The issue is more usability (I miss having automatic typescript types personally) and do wish this package could be released in a similar way to how the typescript types are packaged. As mentioned above, it is still possible to build extensions in MV3 that use google apis, it is just a bit less fast and maintainable.

@zamiang I already know this things. Also as I said we can't every make api calls in terms of url. That's why I am asking @dotproto to provide some solution in MV3 extension. Also this discussion is not about making api calls from extension i don't know what are you trying to prove here 🤷🏻‍♂️. Everyone here wants to get some way to use GAPI and some other 3rd party scripts which are not locally available

nathandpeterson commented 3 years ago

Just want to add another voice here and check to see if there are any updates on this issue. We use maps.googleapis.com in our extension and we'd love to continue to use it in MV3 but it looks like the new CSP prohibits it. @dotproto Is there a solution in the works or a workaround that you recommend?

twschiller commented 3 years ago

In the PixieBrix extension, we use GAPI for the following so far:

References:

e-roy commented 3 years ago

To just be able to have a user log in with popup. I can make it work in MV2, but MV3 would be great! I'm using:

const googleProvider = new firebase.auth.GoogleAuthProvider()
firebase.auth() .signInWithPopup(googleProvider)

manifest.json :

  "content_security_policy": {
    "extension_pages": "script-src 'self'; script-src-elem 'self' https://apis.google.com https://www.gstatic.com https://www.googleapis.com https://securetoken.googleapis.com; object-src 'self';"
  },

and I get back in my console log an error:

Refused to load the script 'https://apis.google.com/js/api.js?onload=__iframefcb41660' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

@dotproto I love everything about firebase, if you could just get the PM from firebase and PM from chrome extensions together for coffee once a week I'll buy the coffee. :)

So many possibilities could be built using firebase in extensions

luciferpd13 commented 3 years ago

@dotproto Any updates on this issue ?

kospl commented 2 years ago

Looks like it's now deprecated and being replaced.

From https://developers.google.com/identity/gsi/web/guides/migration#object_migration_reference_for_user_sign-in

JavaScript libraries Old New Notes
apis.google.com/js/platform.js accounts.google.com/gsi/client Replace old with new.
apis.google.com/js/api.js accounts.google.com/gsi/client Replace old with new.

So a question is now changed to what kind of support of Chrome MV3 new library will have.

rendomnet commented 2 years ago

@e-roy Did you found solution? I'm migrating from manifest2 to manifest3. And have same problem.

apena94 commented 2 years ago

manifest v2 is being deprecated, will there be a solution for this in v3? In my particular use case i would like to have access to reCaptcha from the extension.

https://developer.chrome.com/docs/extensions/mv3/mv2-sunset/

nielm commented 2 years ago

I got some (disappointing) clarification from the GAPI team that chrome extensions are not and will not be a supported environment.

The documentation has been updated in #795 https://github.com/google/google-api-javascript-client/blob/master/docs/start.md#supported-environments

merchalex commented 2 years ago

@dotproto Late reply to your thread, but I have a question. Is the ablity to use the file picker removed entirely from v3? I cannot seem to find a ton of discussion on this specific feature.

Thank you

eliasab16 commented 2 years ago

@nielm so does this mean that we can no longer use gapi in Chrome Extensions? Or were you able to find some workarounds?

j-d-carmichael commented 2 years ago

Seems that way @eliasab16 https://github.com/google/google-api-javascript-client/commit/8c955154dc578eb880481cfb0a8b38bbdbfba0ba

@nielm do you happen to know if this restriction for Google's own code/APIs will be lifted at any point in the future?

We would really like to use the JS Google Maps in our Chrome ext.

george-thomas-hill commented 1 year ago

(Subscribing to this thread.)

darbid commented 1 year ago

MV3 produces another inexplicable result. You cannot use Google’s own APIs in a chrome extension by virtue of the way they are packaged but you can make http requests all day long. Who ever is making these decisions needs to be let go.

albertpratomo commented 11 months ago

@dotproto In the productivity Chrome extension I'm building I want to use GAPI to auth the user, and fetch their Google Calendar events.

image

Isn't it a good idea to whitelist script-src from google.com domain? This way Chrome extension developers can consume Google APIs more easily.

nielm commented 11 months ago

For Auth, the chrome.identity API performs all the wrapping you need to handle oauth.

But then you have to write your own code to call the REST APIs directly using fetch() including handling Auth rejections...

There is an example here

https://developer.chrome.com/docs/extensions/mv3/tut_oauth/

It's not great and means that you cannot use all the predefined types that gapi would give, but it is at least a solution....

enmanuelmag commented 9 months ago

(Subscribing to this thread)

DaisyXten commented 8 months ago

Fine it seems gapi is deprecated in manifestv3 but a lot of samples (updated recently) in official documents are still using gapi, at least write some notes above those samples. I think I saw this thread before, but after some time I go to refer to official doc and see gapi again. I tried, met obstacles, google around and get back to this page again... : (

patrickkettner commented 8 months ago

What samples?

e-roy commented 8 months ago

Fix for Chrome Extensions and Firebase MV3

import { initializeApp } from "firebase/app";
import { initializeAuth } from "firebase/auth";

const app = initializeApp(firebaseConfig);

export const auth = initializeAuth(app, { popupRedirectResolver: undefined });

Hope this helps everyone :)

DaisyXten commented 8 months ago

What samples?

Like this: https://developers.google.com/drive/picker/guides/overview and this: https://developers.google.com/drive/api/quickstart/js use gapi

passwordslug commented 8 months ago

Extension examples are here:

https://github.com/GoogleChrome/chrome-extensions-samples

I don't think there are GAPI MV3 examples.

patrickkettner commented 8 months ago

@e-roy thanks for sharing! We actually made an extension specific channel in firebase auth, so those steps are no longer needed (unless you have a hard dependency on an old version of firebase)

@lidanqing-i neither of those are extensions, so they are not impacted by manifest v3 changes.

rast22 commented 5 months ago

Hi everyone, does any body found any general workaround for this issue. Our extension sometimes requires solving captcha, but with Manifest V3, it is impossible to load recaptcha script https://www.google.com/recaptcha/api.js...

Снимок экрана 2024-05-13 в 20 21 03

patrickkettner commented 5 months ago

Hey @rast22

There is firebase documentation on how to handle this.

e-roy commented 4 months ago

@e-roy thanks for sharing! We actually made an extension specific channel in firebase auth, so those steps are no longer needed (unless you have a hard dependency on an old version of firebase)

@lidanqing-i neither of those are extensions, so they are not impacted by manifest v3 changes.

@patrickkettner thank you very much! I wish I knew how to join the discussion in this channel.

Does the auth work for emulators in a extension?

I'm using connectAuthEmulator(auth, "http://localhost:9099"); but for some reason only when using in an extension it doesn't seem to work for me.