是否可以使用 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 URI
:https://<EXTENSION_OR_APP_ID>.chromiumapp.org
。 URI 不必存在,chrome 只会捕获到此 URL 的重定向并稍后调用您的回调函数。
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(用于 OpenID Connect)文档:https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
PS:如果您不需要清单中的 oauth2 部分。您可以放心地省略它,并仅在代码中提供标识符和范围。
编辑: 对于那些感兴趣的人,您不需要身份 API。您甚至可以使用 tabs API 的小技巧来访问令牌。代码有点长,但是你有更好的错误信息和控制。请记住,在以下示例中,您需要创建 Chrome 应用 凭据。
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);
);
【讨论】:
嗨皮奥特。我已经尝试了您的解决方案,但我收到 无法加载授权页面 错误。我正在做你正在做的事情,清单中的范围相同。 嗨@Aegidius,你知道了吗?我有同样的问题。谢谢。 @Aegidius,这里也一样,不知道这个方法是否还有效? 需要对此进行两处更改。 1) 新的端点基础是https://accounts.google.com/o/oauth2/v2/auth
2) nonce
是身份验证 URL 的必需 URL 参数,所以添加类似 &nonce=<your nonce value>
id_token
建议在将用户信息从扩展程序传送到后端服务器时(此处概述:developers.google.com/identity/sign-in/web/backend-auth)。不过,我这辈子都无法正常工作,因为我收到消息“无效重定向:在提交之前必须将域添加到授权域列表中”。尝试从凭据控制台创建 OAuth Web 客户端时。将扩展程序的 URL 添加到授权域不起作用,因为域“必须是***私有域”。好像是第 22 条军规……不知道该怎么办。【参考方案2】:
首先,我假设在您的 manifest.json sn-p 中,您的 client_id 并不是字面上的 "<chrome-app-client-id>.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 网页,打开空白的问题
是否可以从 WinForm/WPF C# App 与 Web 浏览器进行交互?