From db2d2314767421e5428a4fed780d0299fe2b49a1 Mon Sep 17 00:00:00 2001 From: ljjlee Date: Thu, 20 Mar 2025 15:17:39 +0100 Subject: [PATCH] Add sample Identity API extension (#1432) * Initial copy of _archive/apps/samples/identity * Modify to run be an extension rather than a Chrome App. * Update extension to manifest v3 * Update README * Remove references to chrome://identity-internals * Use Promises rather than callbacks See https://developer.chrome.com/docs/extensions/develop/migrate/api-calls#replace-callbacks * Apply code-review markups. * Apply more code-review markups * Format with prettier * Use Promise.catch instead of runtime.lastError * Update screenshot --------- Co-authored-by: Oliver Dunk --- api-samples/identity/README.md | 21 +++ api-samples/identity/assets/screenshot.png | Bin 0 -> 69973 bytes api-samples/identity/identity.js | 197 +++++++++++++++++++++ api-samples/identity/index.html | 30 ++++ api-samples/identity/main.js | 6 + api-samples/identity/manifest.json | 17 ++ api-samples/identity/style.css | 98 ++++++++++ 7 files changed, 369 insertions(+) create mode 100644 api-samples/identity/README.md create mode 100644 api-samples/identity/assets/screenshot.png create mode 100755 api-samples/identity/identity.js create mode 100755 api-samples/identity/index.html create mode 100755 api-samples/identity/main.js create mode 100755 api-samples/identity/manifest.json create mode 100644 api-samples/identity/style.css diff --git a/api-samples/identity/README.md b/api-samples/identity/README.md new file mode 100644 index 00000000..aed08b90 --- /dev/null +++ b/api-samples/identity/README.md @@ -0,0 +1,21 @@ +# chrome.identity + +A sample extension that uses the +[Identity API](https://developer.chrome.com/docs/extensions/reference/api/identity) +to request information of the logged in user and present this info on the +screen. If the user has a profile picture, their profile image is also fetched +and shown in the app. + +## Overview + +This extension uses the getAuthToken flow of the Identity API, so it only +works with Google accounts. If you want to identify the user in a non-Google +OAuth2 flow, you should use the launchWebAuthFlow method instead. + +![screenshot](assets/screenshot.png) + +## Running this extension + +1. Clone this repository. +2. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +3. Click the extension icon to open the UI. diff --git a/api-samples/identity/assets/screenshot.png b/api-samples/identity/assets/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..758a5f8dc77ecb39648d4f2441c15f5a1f0aacc9 GIT binary patch literal 69973 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 literal 0 HcmV?d00001 diff --git a/api-samples/identity/identity.js b/api-samples/identity/identity.js new file mode 100755 index 00000000..6f5a949c --- /dev/null +++ b/api-samples/identity/identity.js @@ -0,0 +1,197 @@ +'use strict'; + +function onLoad() { + const STATE_START = 1; + const STATE_ACQUIRING_AUTHTOKEN = 2; + const STATE_AUTHTOKEN_ACQUIRED = 3; + + let state = STATE_START; + + const signin_button = document.querySelector('#signin'); + signin_button.addEventListener('click', interactiveSignIn); + + const userinfo_button = document.querySelector('#userinfo'); + userinfo_button.addEventListener( + 'click', + getUserInfo.bind(userinfo_button, true) + ); + + const revoke_button = document.querySelector('#revoke'); + revoke_button.addEventListener('click', revokeToken); + + const user_info_div = document.querySelector('#user_info'); + + // Trying to get user's info without signing in, it will work if the + // application was previously authorized by the user. + getUserInfo(false); + + function disableButton(button) { + button.setAttribute('disabled', 'disabled'); + } + + function enableButton(button) { + button.removeAttribute('disabled'); + } + + function changeState(newState) { + state = newState; + switch (state) { + case STATE_START: + enableButton(signin_button); + disableButton(userinfo_button); + disableButton(revoke_button); + break; + case STATE_ACQUIRING_AUTHTOKEN: + displayOutput('Acquiring token...'); + disableButton(signin_button); + disableButton(userinfo_button); + disableButton(revoke_button); + break; + case STATE_AUTHTOKEN_ACQUIRED: + disableButton(signin_button); + enableButton(userinfo_button); + enableButton(revoke_button); + break; + } + } + + function displayOutput(message) { + let messageStr = message; + if (typeof message != 'string') { + messageStr = JSON.stringify(message); + } + + document.getElementById('__logarea').value = messageStr; + } + + function fetchWithAuth(method, url, interactive, callback) { + let access_token; + let retry = true; + + getToken(); + + function getToken() { + chrome.identity + .getAuthToken({ interactive: interactive }) + .then((token) => { + access_token = token.token; + requestStart(); + }) + .catch((error) => { + callback(error.message); + }); + } + + function requestStart() { + fetch(url, { + method: method, + headers: { + Authorization: 'Bearer ' + access_token + } + }).then((response) => { + if (response.status == 401 && retry) { + retry = false; + chrome.identity + .removeCachedAuthToken({ token: access_token }) + .then(getToken); + } else { + callback(null, response.status, response); + } + }); + } + } + + function getUserInfo(interactive) { + // See https://developers.google.com/identity/openid-connect/openid-connect#obtaininguserprofileinformation + fetchWithAuth( + 'GET', + 'https://openidconnect.googleapis.com/v1/userinfo', + interactive, + onUserInfoFetched + ); + } + + // Code updating the user interface, when the user information has been + // fetched or displaying the error. + function onUserInfoFetched(error, status, response) { + if (!error && status == 200) { + changeState(STATE_AUTHTOKEN_ACQUIRED); + response.json().then((user_info) => { + displayOutput(user_info); + populateUserInfo(user_info); + }); + } else { + changeState(STATE_START); + } + } + + function populateUserInfo(user_info) { + if (!user_info || !user_info.picture) return; + + user_info_div.innerText = 'Hello ' + user_info.name; + + const imgElem = document.createElement('img'); + imgElem.src = user_info.picture; + imgElem.style.width = '24px'; + user_info_div.insertAdjacentElement('afterbegin', imgElem); + } + + // OnClick event handlers for the buttons. + + /** + Retrieves a valid token. Since this is initiated by the user + clicking in the Sign In button, we want it to be interactive - + ie, when no token is found, the auth window is presented to the user. + + Observe that the token does not need to be cached by the app. + Chrome caches tokens and takes care of renewing when it is expired. + In that sense, getAuthToken only goes to the server if there is + no cached token or if it is expired. If you want to force a new + token (for example when user changes the password on the service) + you need to call removeCachedAuthToken() + **/ + function interactiveSignIn() { + changeState(STATE_ACQUIRING_AUTHTOKEN); + console.log('interactiveSignIn'); + + // This is the normal flow for authentication/authorization on Google + // properties. You need to add the oauth2 client_id and scopes to the app + // manifest. The interactive param indicates if a new window will be opened + // when the user is not yet authenticated or not. + // + // See https://developer.chrome.com/docs/extensions/reference/api/identity#method-getAuthToken + chrome.identity + .getAuthToken({ interactive: true }) + .then((token) => { + displayOutput('Token acquired:\n' + token.token); + changeState(STATE_AUTHTOKEN_ACQUIRED); + }) + .catch((error) => { + displayOutput(error.message); + changeState(STATE_START); + }); + } + + function revokeToken() { + user_info_div.innerHTML = ''; + chrome.identity + .getAuthToken({ interactive: false }) + .then((current_token) => { + // Remove the local cached token + chrome.identity.removeCachedAuthToken({ token: current_token.token }); + + // Make a request to revoke token in the server. + // See https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#tokenrevoke + fetch( + 'https://oauth2.googleapis.com/revoke?token=' + current_token.token, + { method: 'POST' } + ).then(() => { + // Update the user interface accordingly + changeState(STATE_START); + displayOutput('Token revoked and removed from cache.'); + }); + }); + } +} + +window.addEventListener('load', onLoad); diff --git a/api-samples/identity/index.html b/api-samples/identity/index.html new file mode 100755 index 00000000..d3f50ebb --- /dev/null +++ b/api-samples/identity/index.html @@ -0,0 +1,30 @@ + + + Identity API Sample Extension + + + + +
+

Identity API

+ +
+
+
+

OAuth on Google properties

+
+ + + +
+
+
+
+ +
+ + diff --git a/api-samples/identity/main.js b/api-samples/identity/main.js new file mode 100755 index 00000000..9ad9eff7 --- /dev/null +++ b/api-samples/identity/main.js @@ -0,0 +1,6 @@ +chrome.action.onClicked.addListener(() => { + chrome.tabs.create({ + active: true, + url: "index.html" + }) +}) \ No newline at end of file diff --git a/api-samples/identity/manifest.json b/api-samples/identity/manifest.json new file mode 100755 index 00000000..d435e2d7 --- /dev/null +++ b/api-samples/identity/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "Identity API Sample", + "version": "4.0", + "manifest_version": 3, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDJB6ZGcGxtlr/34s+TKgi84QiP7DMekqOjSUS2ubmbhchlM6CN9gYdGQ1aBI3TBXG3YaAu+XyutFA8M8NLLWc4OOGByWaGV11DP6p67g8a+Ids/gX6cNSRnRHiDZXAd44ATxoN4OZjZJk9iQ26RIUjwX07bzntlI+frwwKCk4WQIDAQAB", + "action": {}, + "background": { + "service_worker": "main.js" + }, + "permissions": ["identity"], + "oauth2": { + // client_id below is specific to the application key. Follow the + // documentation to obtain one for your app. + "client_id": "497291774654.apps.googleusercontent.com", + "scopes": ["https://www.googleapis.com/auth/userinfo.profile"] + } +} diff --git a/api-samples/identity/style.css b/api-samples/identity/style.css new file mode 100644 index 00000000..7d6a98e1 --- /dev/null +++ b/api-samples/identity/style.css @@ -0,0 +1,98 @@ +html, body { + margin: 0; + font-family: 'Open Sans Regular', sans; + color: #666; + background: #fafafa; +} + +.header { + text-align: center; + padding: 10px 0 10px 0; +} + +.header hr { + height: 6px; + border: none; + margin-top: 20px; + background: -webkit-linear-gradient(0deg, + rgb(51,105,232) 0%, + rgb(51,105,232) 25%, + rgb(222,30,37) 25%, + rgb(222,30,37) 50%, + rgb(255, 210, 0) 50%, + rgb(255, 210, 0) 75%, + rgb(76,187,71) 75%, + rgb(76,187,71) 100% + ); + } + +.header .links * { + margin-left: 5px; +} + +.header .links a { + color: #666; +} + +.header:hover .links a { + color: #3399cc; +} + +.flows h2 { + margin-left: 5px; + margin-bottom: 10px; +} + +.flow { + margin: 10px 20px 20px 20px; + border: 1px solid #ddd; + padding: 8px; + background: white; +} + +.flow button { + cursor: pointer; + background: -webkit-linear-gradient(top,#008dfd 0,#0370ea 100%); + border: 1px solid #076bd2; + text-shadow: 1px 1px 1px #076bd2; + color: white; + font-weight: 700; + font-size: 13px; + margin: .5em 0 1em; + padding: 8px 17px 8px 17px; + border-radius: 3px; +} + +.flow button.error { + background: -webkit-linear-gradient(top,#008dfd 0,#0370ea 100%); + border: 1px solid #076bd2; + text-shadow: 1px 1px 1px #076bd2; + color: white; + font-weight: 700; + font-size: 13px; + margin: .5em 0 1em; + padding: 8px 17px 8px 17px; + border-radius: 3px; +} + +.flow button:disabled { + background: -webkit-linear-gradient(top, #dcdcdc 0, #fafafa 100%); + color: #999; + text-shadow: 1px 1px 1px #fafafa; + border: 1px solid #ddd; + cursor: auto; +} + +.log { + margin: 10px 20px 20px 20px; +} + +.log textarea { + width: 100%; + min-height: 200px; + font-family: "Courier New", Courier, monospace; + margin: 2px; + background: #FFFFFF; + color: #727272; + border: 1px solid rgb(182, 182, 182); +}