Is it possible to get an Id token with Chrome App Indentity Api?

前端 未结 3 1449
生来不讨喜
生来不讨喜 2020-12-03 01:20

I can\'t get a user\'s id_token (https://developers.google.com/accounts/docs/CrossClientAuth) from the Chrome identity api (https://developer.chrome.com/apps/identity).

相关标签:
3条回答
  • 2020-12-03 02:05

    I've came to the same problem yesterday and since I've found a solution, I might as well share it, as it wasn't that obvious. As far as i know Google does not provide a direct and documented way to do this, but you can use the chrome.identity.launchWebAuthFlow() function.

    First you should create an Web application credentials in google console and add the following url as a valid Authorized redirect URI: https://<EXTENSION_OR_APP_ID>.chromiumapp.org. The URI does not have to exist, chrome will just catch the redirect to this URL and call your callback function later.

    manifest.json:

    {
      "manifest_version": 2,
      "name": "name",
      "description": "description",
      "version": "0.0.0.1",
      "background": {
        "scripts": ["background.js"]
      },
      "permissions": [
        "identity"
      ],
      "oauth2": {
        "client_id": "<CLIENT_ID>.apps.googleusercontent.com",
        "scopes": [
          "openid", "email", "profile"
        ]
      }
    }
    

    background.js:

    // Using chrome.identity
    var manifest = chrome.runtime.getManifest();
    
    var clientId = encodeURIComponent(manifest.oauth2.client_id);
    var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
    var redirectUri = encodeURIComponent('https://' + chrome.runtime.id + '.chromiumapp.org');
    
    var url = 'https://accounts.google.com/o/oauth2/auth' + 
              '?client_id=' + clientId + 
              '&response_type=id_token' + 
              '&access_type=offline' + 
              '&redirect_uri=' + redirectUri + 
              '&scope=' + scopes;
    
    chrome.identity.launchWebAuthFlow(
        {
            'url': url, 
            'interactive':true
        }, 
        function(redirectedTo) {
            if (chrome.runtime.lastError) {
                // Example: Authorization page could not be loaded.
                console.log(chrome.runtime.lastError.message);
            }
            else {
                var response = redirectedTo.split('#', 2)[1];
    
                // Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
                console.log(response);
            }
        }
    );
    

    Google OAuth2 API (for OpenID Connect) documentation can be found here: https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters

    PS: If you don't need the oauth2 section in your manifest. You can safely omit it, and provide the identifiers and scopes in code only.

    EDIT: For those interested, you don't need the identity API. You can even access the token using a little trick with tabs API. The code is a little longer, but you have better error messages and control. Keep in mind that in the following example, you need to create Chrome App credentials.

    manifest.json:

    {
      "manifest_version": 2,
      "name": "name",
      "description": "description",
      "version": "0.0.0.1",
      "background": {
        "scripts": ["background.js"]
      },
      "permissions": [
        "tabs"
      ],
      "oauth2": {
        "client_id": "<CLIENT_ID>.apps.googleusercontent.com",
        "scopes": [
          "openid", "email", "profile"
        ]
      }
    }
    

    background.js:

    // Using chrome.tabs
    var manifest = chrome.runtime.getManifest();
    
    var clientId = encodeURIComponent(manifest.oauth2.client_id);
    var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
    var redirectUri = encodeURIComponent('urn:ietf:wg:oauth:2.0:oob:auto');
    
    var url = 'https://accounts.google.com/o/oauth2/auth' + 
              '?client_id=' + clientId + 
              '&response_type=id_token' + 
              '&access_type=offline' + 
              '&redirect_uri=' + redirectUri + 
              '&scope=' + scopes;
    
    var RESULT_PREFIX = ['Success', 'Denied', 'Error'];
    chrome.tabs.create({'url': 'about:blank'}, function(authenticationTab) {
        chrome.tabs.onUpdated.addListener(function googleAuthorizationHook(tabId, changeInfo, tab) {
            if (tabId === authenticationTab.id) {
                var titleParts = tab.title.split(' ', 2);
    
                var result = titleParts[0];
                if (titleParts.length == 2 && RESULT_PREFIX.indexOf(result) >= 0) {
                    chrome.tabs.onUpdated.removeListener(googleAuthorizationHook);
                    chrome.tabs.remove(tabId);
    
                    var response = titleParts[1];
                    switch (result) {
                        case 'Success':
                            // Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
                            console.log(response);
                        break;
                        case 'Denied':
                            // Example: error_subtype=access_denied&error=immediate_failed
                            console.log(response);
                        break;
                        case 'Error':
                            // Example: 400 (OAuth2 Error)!!1
                            console.log(response);
                        break;
                    }
                }
            }
        });
    
        chrome.tabs.update(authenticationTab.id, {'url': url});
    });
    
    0 讨论(0)
  • 2020-12-03 02:05

    First, I assume that in your manifest.json snippet you don't mean that your client_id is literally "<chrome-app-client-id>.apps.googleusercontent.com. It should be something like 9414861317621.apps.googleusercontent.com -- something you got from the Developer Console, or whatever Google site you used to register the app.

    Assuming the above is OK, and you have the client_id right, and the scope right, you get what's called an "OAuth2 access token" with a call to chrome.identity.getAuthToken. As you don't show us any JavaScript code, I can't tell if this is what you're doing. The access token you get you need to save for subsequent use when you call an API function. For example:

    var access_token;
    
    chrome.identity.getAuthToken(
        {
            'interactive': true
        },
        function(token) {
            access_token = token;
            // do something if you like to indicate
            // that the app is authorized
        }
    );
    

    Then, when you make an API call, you supply that access token, like this:

    var url = 'https://www.googleapis.com/' + method;
    Ajax.ajaxSend(url, "json",
        function (status, response) {
            if (response && response.error && response.error.message)
                errorCallback(response.error.message);
            else if (status == 200)
                successCallback(response);
            else
                errorCallback('Result code: ' + status);
        },
        function (e) {
            if (errorCallback)
                errorCallback('Communication error');
        },
        {
            Authorization: 'Bearer ' + access_token
        }
    );
    

    Ajax.ajaxSend is my own function:

    var Ajax = (function () {
        var api = {
            ajaxSend: function (url, responseType, successCallback, errorCallback, headers) {
                var req = new XMLHttpRequest();
                req.onload = function (e) {
                    successCallback(req.status, req.response);
                };
                req.onerror = errorCallback;
                req.responseType = responseType ? responseType : "text";
                req.open("get", url);
                if (headers)
                    for (var v in headers)
                        req.setRequestHeader(v, headers[v]);
                req.send();
            }
        };
        return api;
    })();
    

    The other undefined functions also are what you'd expect. The third argument to Ajax.ajaxSend is a header to be sent along. (Sorry, I don't have time to develop standalone code just for this answer.)

    I hope the above is useful.

    0 讨论(0)
  • 2020-12-03 02:15

    I guess it depends on why one would want token id, but in my case access_token was enough to authorize user - by pulling user info from https://www.googleapis.com/oauth2/v2/userinfo?alt=json ( with Authorization header = access_token).

    0 讨论(0)
提交回复
热议问题