Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to set up user authentication for a Chrome Extension using the Chrome Identity API

How to set up user authentication for a Chrome Extension using the Chrome Identity API

  1. Create a private key file, from which you can create the manifest key and Application ID, as detailed here: https://stackoverflow.com/questions/23873623/obtaining-chrome-extension-id-for-development
  2. Add the manifest key to "key" in manifest.json
  3. Create a new project in Google Developer Console https://console.developers.google.com/project
  4. Go to "APIs & auth > Credentials" and create new client id for a Chrome Application using the Application ID generated in step 3.
  5. Copy the Client ID to oauth2.client_id in the manifest.json

Deprecated?

  1. Create a new app on the Chrome Web Store Developer Dashboard https://chrome.google.com/webstore/developer/dashboard
  2. Click on "more info" and copy the public key to "key" in manifest.json. (or not needed because of next step...?)

Resources

chrome.identity.getAuthToken({
interactive: true
}, function(token) {
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
var x = new XMLHttpRequest();
x.open('GET', 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + token);
x.onload = function() {
alert(x.response);
};
x.send();
});
{
"key": "<Application ID>",
"name": "Identity test",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions": [
"identity"
],
"oauth2": {
"client_id": "<Client ID>",
"scopes": [
"https://www.googleapis.com/auth/userinfo.email"
]
}
}
@herodrigues

This comment has been minimized.

Copy link

@herodrigues herodrigues commented Feb 28, 2019

Chrome Apps are deprecated, but this works on Chrome extensions too.

You can also only upload (not publish!) an extension to the Chrome Strore, then click on More info to get the private key
Thanks!

@herodrigues

This comment has been minimized.

Copy link

@herodrigues herodrigues commented Feb 28, 2019

I also tried that approach with identity.launchWebFlow, but it doesn't work if I use the value returned from identity.getRedirectURL as redirectURL parameter.

// const redirectURL = browser.identity.getRedirectURL()

const scopes = ['email']
let authURL = 'https://accounts.google.com/o/oauth2/auth'
authURL += `?client_id=${clientId}`
authURL += `&response_type=token`
authURL += `&redirect_uri=${encodeURIComponent('http://localhost')}`
authURL += `&scope=${encodeURIComponent(scopes.join(' '))}`

browser.identity.launchWebAuthFlow({
  url: authURL,
  interactive: true
})

I'm calling this piece of code in my background page from an action triggered in the content script. It doesn't work if I set redirect_uri to sender.tab.url (from the runtime.onMessage listener) either.
It works only if I use localhost 😕

I don't need the private key for though.
My extension is loaded in development mode. That's maybe the for that?
Who knows...

Couldn't find anything in the docs.

@kairyou

This comment has been minimized.

Copy link

@kairyou kairyou commented Feb 6, 2020

for launchWebFlow

  • Create OAuth client ID, Application type: Web application, Authorized redirect URIs: https://<extension-id>.chromiumapp.org/
global.browser = require('webextension-polyfill'); // https://git.io/Jve8X
const redirectURL = browser.identity.getRedirectURL();
const { oauth2 } = browser.runtime.getManifest();
const clientId = oauth2.client_id;
const authParams = new URLSearchParams({
  client_id: clientId,
  response_type: 'token',
  redirect_uri: redirectURL,
  scope: ['email'].join(' '),
});
const authURL = `https://accounts.google.com/o/oauth2/auth?${authParams.toString()}`;
browser.identity.launchWebAuthFlow({ url: authURL, interactive: true }).then((responseUrl) => {
  console.warn({ responseUrl, authURL });
  const url = new URL(responseUrl);
  const urlParams = new URLSearchParams(url.hash.slice(1));
  const params = Object.fromEntries(urlParams.entries()); // access_token, expires_in
  fetch(`https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${params.access_token}`, {
    method: 'GET',
    headers: { 'Content-Type': 'application/json' },
  }).then(response => response.json()).then((data) => {
    alert(JSON.stringify(data));
  });
}).catch((error) => {
  console.warn(error.message, authURL);
});
  • manifest.json
"permissions": [ "identity" ],
"oauth2": {
  "client_id": "***.apps.googleusercontent.com", // Client ID
  "scopes": ["https://www.googleapis.com/auth/userinfo.email"]
}
@jkcorrea

This comment has been minimized.

Copy link

@jkcorrea jkcorrea commented Feb 25, 2020

For anyone reading this, make sure to include the trailing / when authorizing the https://<extension-id>.chromiumapp.org/ in Google dev console. I just spent the better part of an hour debugging my failing auth flow until I realized I was thinking too hard...

Thanks @kairyou and @raineorshine for the examples!

@LispyAriaro

This comment has been minimized.

Copy link

@LispyAriaro LispyAriaro commented Mar 5, 2020

Thanks so much. This gist was EXACTLY what I needed. I spent so much time everywhere else.
Google's site here: https://developer.chrome.com/apps/app_identity ... showed how to get the token but not how to use the token to retrieve some data. Almost useless. Thank you again for this gist.

@garridio85

This comment has been minimized.

Copy link

@garridio85 garridio85 commented Jul 9, 2020

This is a great explanation!

Do you know how I can refresh the access token by any chance? When I try to run the same call with interactive: false it throws an error saying user not logged in.

I know the user is logged in as I have all their info and an active session.

Any advice would be greatly appreciated.

@bartoszluczak

This comment has been minimized.

Copy link

@bartoszluczak bartoszluczak commented Sep 10, 2020

for launchWebFlow

  • Create OAuth client ID, Application type: Web application, Authorized redirect URIs: https://<extension-id>.chromiumapp.org/
const redirectURL = browser.identity.getRedirectURL();
const { oauth2 } = browser.runtime.getManifest();
const clientId = oauth2.client_id;
const authParams = new URLSearchParams({
  client_id: clientId,
  response_type: 'token',
  redirect_uri: redirectURL,
  scope: ['email'].join(' '),
});
const authURL = `https://accounts.google.com/o/oauth2/auth?${authParams.toString()}`;
browser.identity.launchWebAuthFlow({ url: authURL, interactive: true }).then((responseUrl) => {
  console.warn({ responseUrl, authURL });
  const url = new URL(responseUrl);
  const urlParams = new URLSearchParams(url.hash.slice(1));
  const params = Object.fromEntries(urlParams.entries()); // access_token, expires_in
  fetch(`https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${params.access_token}`, {
    method: 'GET',
    headers: { 'Content-Type': 'application/json' },
  }).then(response => response.json()).then((data) => {
    alert(JSON.stringify(data));
  });
}).catch((error) => {
  console.warn(error.message, authURL);
});

Great post by how should looks manifest file?

@mikeyyyzhao

This comment has been minimized.

Copy link

@mikeyyyzhao mikeyyyzhao commented Oct 4, 2020

Has this changed in the last few weeks? It looks like launchWebAuthFlow is no longer a promise and we need to pass in a call back function instead as the second parameter. Otherwise, this errors out with an invocation error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.