是否可以使用 Chrome App Indentity Api 获取 Id 令牌?

Posted

技术标签:

【中文标题】是否可以使用 Chrome App Indentity Api 获取 Id 令牌?【英文标题】:Is it possible to get an Id token with Chrome App Indentity Api? 【发布时间】:2014-12-03 01:42:01 【问题描述】:

我无法从 Chrome 身份 api (https://developer.chrome.com/apps/identity) 获取用户的 id_token (https://developers.google.com/accounts/docs/CrossClientAuth)。

当清单中的 oauth 部分为:

"oauth2": 
  "client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
  "scopes": ["https://www.googleapis.com/auth/plus.login"]

但是当我尝试以与在我的 android 客户端上获取它相同的方式获取 id_token 时,出现错误:

“OAuth2 请求失败:服务响应错误:'无效范围:0'”

清单部分现在是:

"oauth2": 
  "client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
  "scopes": ["audience:server:client_id:<app-engine-client-id>.apps.googleusercontent.com"]

在 Android 上,我通过将相同的范围字符串传递给 android.gms.auth.GoogleAuthUtil.getToken() 来获取 id_token,但我无法让它与 chrome 身份 api 一起使用。

是否可以使用 Chrome App Indentity Api 获取 id_token?如果没有,我怎样才能为我的 Chrome 应用获取 id_token?

感谢您的帮助!

【问题讨论】:

OAuth 的术语很疯狂。在您的帖子中,您指的是“user id”、“client_id”、“id token”和“id”。你能准确地说出你想要得到的究竟是什么吗? (我知道一些关于“client_id”的事情,“id”太笼统了,我无法理解,我不确定“user id”是什么。) 同意,有几个术语需要分开。为了清楚起见,编辑了帖子。 client_id 在帖子的第一个链接中提到,需要在 id_token 中指定受众。我想很明显我想要一个 id_token 可以在附加到 googleapis.com/oauth2/v1/tokeninfo?id_token= 时进行验证 您是否尝试将openid 添加到范围?这通常是使服务器进入 OpenID 连接模式并发出 ID 令牌所需的提示。 【参考方案1】:

我昨天遇到了同样的问题,既然我找到了解决方案,我不妨分享一下,因为它并不那么明显。据我所知,Google 没有提供直接且有记录的方法来执行此操作,但您可以使用 chrome.identity.launchWebAuthFlow() 函数。

首先,您应该在 google 控制台中创建一个 Web 应用程序 凭据,并将以下 url 添加为有效的Authorized redirect URIhttps://&lt;EXTENSION_OR_APP_ID&gt;.chromiumapp.org。 URI 不必存在,chrome 只会捕获到此 URL 的重定向并稍后调用您的回调函数。

ma​​nifest.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(用于 OpenID Connect)文档:https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters

PS:如果您不需要清单中的 oauth2 部分。您可以放心地省略它,并仅在代码中提供标识符和范围。

编辑: 对于那些感兴趣的人,您不需要身份 API。您甚至可以使用 tabs API 的小技巧来访问令牌。代码有点长,但是你有更好的错误信息和控制。请记住,在以下示例中,您需要创建 Chrome 应用 凭据。

ma​​nifest.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);
);

【讨论】:

嗨皮奥特。我已经尝试了您的解决方案,但我收到 无法加载授权页面 错误。我正在做你正在做的事情,清单中的范围相同。 嗨@Aegidius,你知道了吗?我有同样的问题。谢谢。 @Aegidius,这里也一样,不知道这个方法是否还有效? 需要对此进行两处更改。 1) 新的端点基础是 https://accounts.google.com/o/oauth2/v2/auth 2) nonce 是身份验证 URL 的必需 URL 参数,所以添加类似 &amp;nonce=&lt;your nonce value&gt; id_token 建议在将用户信息从扩展程序传送到后端服务器时(此处概述:developers.google.com/identity/sign-in/web/backend-auth)。不过,我这辈子都无法正常工作,因为我收到消息“无效重定向:在提交之前必须将域添加到授权域列表中”。尝试从凭据控制台创建 OAuth Web 客户端时。将扩展程序的 URL 添加到授权域不起作用,因为域“必须是***私有域”。好像是第 22 条军规……不知道该怎么办。【参考方案2】:

首先,我假设在您的 manifest.json sn-p 中,您的 client_id 并不是字面上的 "&lt;chrome-app-client-id&gt;.apps.googleusercontent.com。它应该是 9414861317621.apps.googleusercontent.com 之类的东西——你从开发者控制台获得的东西,或者你用来注册应用程序的任何 Google 网站。

假设上述情况正常,并且您拥有正确的 client_id 和正确的范围,您将通过调用 chrome.identity.getAuthToken 获得所谓的“OAuth2 访问令牌”。由于您没有向我们展示任何 javascript 代码,因此我无法判断这是否是您正在做的事情。当您调用 API 函数时,您需要保存获得的访问令牌以供后续使用。例如:

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
    
);

然后,当您进行 API 调用时,您提供该访问令牌,如下所示:

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是我自己的函数:

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;
)();

其他未定义的函数也是您所期望的。 Ajax.ajaxSend 的第三个参数是要发送的标头。 (抱歉,我没有时间为这个答案开发独立代码。)

希望以上内容有用。

【讨论】:

感谢您提供帮助,但这不是我的问题的答案。在第 3 行的问题中,我说我知道如何获取 access_token(我将其包括在内以避免解释如何获取的答案)。我想要得到的是一个 id_token (一个可以在附加到这个 url 时验证的令牌:“googleapis.com/oauth2/v1/tokeninfo?id_token=" ) 你有没有想过这个问题?我也在尝试做同样的事情。谢谢。 仍在为此苦苦挣扎:/【参考方案3】:

我想这取决于为什么需要令牌 ID,但在我的情况下 access_token 足以授权用户 - 通过从 https://www.googleapis.com/oauth2/v2/userinfo?alt=json 提取用户信息(授权标头 = access_token)。

【讨论】:

id_token 可以传递给服务器说“是的,我是这个用户 - 谷歌说我是,并且我打算将此批准用于您的应用程序(项目 client_id),并且您可以使用 google 的公开 .well-known 证书来验证声明”

以上是关于是否可以使用 Chrome App Indentity Api 获取 Id 令牌?的主要内容,如果未能解决你的问题,请参考以下文章

怎么使用chrome调试andriod app(Hybrid App)

chrome浏览器使用chrome://inspect调试app 网页,打开空白的问题

烧瓶登录:Chrome 忽略 cookie 过期?

是否可以从 WinForm/WPF C# App 与 Web 浏览器进行交互?

无法使用 Chrome 登录 Dot Net Core 3 ASP.Net App,但可以使用 Firefox

在 C# App 中嵌入 Chrome 浏览器使用 CefSharp