mirror of
https://github.com/mdn/webextensions-examples.git
synced 2026-04-16 06:18:35 +02:00
Added an example using the identity API (#180)
* Added an example using the identity API * Updated with review comment fixes
This commit is contained in:
33
google-userinfo/README.md
Normal file
33
google-userinfo/README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# google-userinfo
|
||||||
|
|
||||||
|
This add-on fetches the user's info from their Google account and displays their name in a notification.
|
||||||
|
|
||||||
|
In detail, it adds a browser action. When the user clicks the browser action, the add-on:
|
||||||
|
|
||||||
|
* uses `identity.launchWebAuthFlow()` to get an access token from Google. This asks the user to sign into Google, if they are not already signed in (authentication), then asks the user if they grant the WebExtension permission to get their user info, if the user has not already granted this permission (authorization).
|
||||||
|
|
||||||
|
* validates the access token
|
||||||
|
|
||||||
|
* passes the access token into a Google API that returns the user's info
|
||||||
|
|
||||||
|
* displays a notification containing the user's name.
|
||||||
|
|
||||||
|
This is following essentially the process documented here: https://developers.google.com/identity/protocols/OAuth2UserAgent.
|
||||||
|
|
||||||
|
## Setup ##
|
||||||
|
|
||||||
|
There's some basic setup you must do before you can use this example.
|
||||||
|
|
||||||
|
* **getting the redirect URL**: this represents the end point of the flow, where the access token is delivered to the WebExtension. The redirect URL is derived from the WebExtension's ID. To get the redirect URL for this example, install it, visit about:addons, and open its "Preferences" page. It will look something like "https://dc6ae45f54e3d55036b819b93a1876228e5f5f7b.extensions.allizom.org/".
|
||||||
|
|
||||||
|
* **registering your add-on with Google as an OAuth2 client**.
|
||||||
|
* Visit https://console.developers.google.com/apis/credentials
|
||||||
|
* Click "Create credentials", and select "OAuth client ID"
|
||||||
|
* Select "Web application", and give it a name. The name is shown to the user to help them understand whether to authorize the add-on.
|
||||||
|
* Paste the redirect URL into the " Authorized redirect URIs" box.
|
||||||
|
* Click "Create"
|
||||||
|
* You'll see a popup containing a Client ID and a secret. Copy the client ID (you can ignore the secret).
|
||||||
|
* Paste this value into authorize.js in place of YOUR-CLIENT-ID.
|
||||||
|
* Reload the add-on.
|
||||||
|
|
||||||
|
Note that because you have to edit authorize.js, we can't provide a prebuilt, presigned version of this add-on in the "builds" directory of this repo, as we can for other examples. So to run this example in Firefox you'll need to use the ["Load Temporary Add-on"](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox) feature, or use the [web-ext](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext) tool.
|
||||||
74
google-userinfo/background/authorize.js
Normal file
74
google-userinfo/background/authorize.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
const REDIRECT_URL = browser.identity.getRedirectURL();
|
||||||
|
const CLIENT_ID = "YOUR-CLIENT-ID";
|
||||||
|
const SCOPES = ["openid", "email", "profile"];
|
||||||
|
const AUTH_URL =
|
||||||
|
`https://accounts.google.com/o/oauth2/auth
|
||||||
|
?client_id=${CLIENT_ID}
|
||||||
|
&response_type=token
|
||||||
|
&redirect_uri=${encodeURIComponent(REDIRECT_URL)}
|
||||||
|
&scope=${encodeURIComponent(SCOPES.join(' '))}`;
|
||||||
|
const VALIDATION_BASE_URL="https://www.googleapis.com/oauth2/v3/tokeninfo";
|
||||||
|
|
||||||
|
function extractAccessToken(redirectUri) {
|
||||||
|
let m = redirectUri.match(/[#\?](.*)/);
|
||||||
|
if (!m || m.length < 1)
|
||||||
|
return null;
|
||||||
|
let params = new URLSearchParams(m[1].split("#")[0]);
|
||||||
|
return params.get("access_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Validate the token contained in redirectURL.
|
||||||
|
This follows essentially the process here:
|
||||||
|
https://developers.google.com/identity/protocols/OAuth2UserAgent#tokeninfo-validation
|
||||||
|
- make a GET request to the validation URL, including the access token
|
||||||
|
- if the response is 200, and contains an "aud" property, and that property
|
||||||
|
matches the clientID, then the response is valid
|
||||||
|
- otherwise it is not valid
|
||||||
|
|
||||||
|
Note that the Google page talks about an "audience" property, but in fact
|
||||||
|
it seems to be "aud".
|
||||||
|
*/
|
||||||
|
function validate(redirectURL) {
|
||||||
|
const accessToken = extractAccessToken(redirectURL);
|
||||||
|
if (!accessToken) {
|
||||||
|
throw "Authorization failure";
|
||||||
|
}
|
||||||
|
const validationURL = `${VALIDATION_BASE_URL}?access_token=${accessToken}`;
|
||||||
|
const validationRequest = new Request(validationURL, {
|
||||||
|
method: "GET"
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkResponse(response) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (response.status != 200) {
|
||||||
|
reject("Token validation error");
|
||||||
|
}
|
||||||
|
response.json().then((json) => {
|
||||||
|
if (json.aud && (json.aud === CLIENT_ID)) {
|
||||||
|
resolve(accessToken);
|
||||||
|
} else {
|
||||||
|
reject("Token validation error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(validationRequest).then(checkResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Authenticate and authorize using browser.identity.launchWebAuthFlow().
|
||||||
|
If successful, this resolves with a redirectURL string that contains
|
||||||
|
an access token.
|
||||||
|
*/
|
||||||
|
function authorize() {
|
||||||
|
return browser.identity.launchWebAuthFlow({
|
||||||
|
interactive: true,
|
||||||
|
url: AUTH_URL
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccessToken() {
|
||||||
|
return authorize().then(validate);
|
||||||
|
}
|
||||||
23
google-userinfo/background/main.js
Normal file
23
google-userinfo/background/main.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
function notifyUser(user) {
|
||||||
|
browser.notifications.create({
|
||||||
|
"type": "basic",
|
||||||
|
"title": "Google info",
|
||||||
|
"message": `Hi ${user.name}`
|
||||||
|
});}
|
||||||
|
|
||||||
|
function logError(error) {
|
||||||
|
console.error(`Error: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
When the button's clicked:
|
||||||
|
- get an access token using the identity API
|
||||||
|
- use it to get the user's info
|
||||||
|
- show a notification containing some of it
|
||||||
|
*/
|
||||||
|
browser.browserAction.onClicked.addListener(() => {
|
||||||
|
getAccessToken()
|
||||||
|
.then(getUserInfo)
|
||||||
|
.then(notifyUser)
|
||||||
|
.catch(logError);
|
||||||
|
});
|
||||||
22
google-userinfo/background/userinfo.js
Normal file
22
google-userinfo/background/userinfo.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
Fetch the user's info, passing in the access token in the Authorization
|
||||||
|
HTTP request header.
|
||||||
|
*/
|
||||||
|
function getUserInfo(accessToken) {
|
||||||
|
const requestURL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
requestHeaders.append('Authorization', 'Bearer ' + accessToken);
|
||||||
|
const driveRequest = new Request(requestURL, {
|
||||||
|
method: "GET",
|
||||||
|
headers: requestHeaders
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetch(driveRequest).then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw response.status;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
1
google-userinfo/icons/LICENSE
Normal file
1
google-userinfo/icons/LICENSE
Normal file
@@ -0,0 +1 @@
|
|||||||
|
The "person-32.png" "person-48.png" icons are taken from the Ionicons iconset (http://ionicons.com/), and are used here under the MIT license: http://opensource.org/licenses/MIT.
|
||||||
BIN
google-userinfo/icons/person-32.png
Normal file
BIN
google-userinfo/icons/person-32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 B |
BIN
google-userinfo/icons/person-48.png
Normal file
BIN
google-userinfo/icons/person-48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 573 B |
41
google-userinfo/manifest.json
Normal file
41
google-userinfo/manifest.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"name": "Google User Info",
|
||||||
|
"version": "1",
|
||||||
|
"manifest_version": 2,
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "google-user-info@mozilla.org",
|
||||||
|
"strict_min_version": "53a1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"icons": {
|
||||||
|
"48": "icons/person-48.png"
|
||||||
|
},
|
||||||
|
|
||||||
|
"browser_action": {
|
||||||
|
"browser_style": true,
|
||||||
|
"default_icon": "icons/person-32.png"
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": [
|
||||||
|
"identity",
|
||||||
|
"notifications",
|
||||||
|
"*://www.googleapis.com/*",
|
||||||
|
"*://accounts.google.com/*"
|
||||||
|
],
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"scripts": [
|
||||||
|
"background/authorize.js",
|
||||||
|
"background/userinfo.js",
|
||||||
|
"background/main.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"options_ui": {
|
||||||
|
"page": "options/options.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
google-userinfo/options/options.html
Normal file
16
google-userinfo/options/options.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div>Redirect URL: <span id="redirect-url"></span></div>
|
||||||
|
|
||||||
|
<script src="options.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
4
google-userinfo/options/options.js
Normal file
4
google-userinfo/options/options.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
Display the redirect URL.
|
||||||
|
*/
|
||||||
|
document.querySelector("#redirect-url").textContent = browser.identity.getRedirectURL();
|
||||||
Reference in New Issue
Block a user