Можно ли получить токен идентификатора с помощью Chrome App Indentity Api?

Я не могу получить id_token пользователя (https://developers.google.com/accounts/docs/CrossClientAuth) из API идентификации Chrome (https://developer.chrome.com/apps/identity ).

Я могу получить access_token, используя образец удостоверения Chrome, когда раздел oauth в манифесте:

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

Но когда я пытаюсь получить id_token так же, как я получаю его на своем клиенте Android, я получаю сообщение об ошибке:

"Ошибка запроса 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 я получаю id_token, передавая ту же строку области действия в android.gms.auth.GoogleAuthUtil.getToken(), но я не могу заставить ее работать с API-интерфейсом идентификации Chrome.

Можно ли получить id_token с помощью Chrome App Indentity Api? Если нет, как я могу получить id_token для своего приложения Chrome?

Спасибо за вашу помощь!


comment
Терминология OAuth сумасшедшая. В своем сообщении вы ссылаетесь на идентификатор пользователя, client_id, токен идентификатора и идентификатор. Можете ли вы быть точным в отношении того, что именно вы пытаетесь получить? (Я знаю кое-что о client_id, идентификатор слишком общий для меня, чтобы понять, и я не уверен, что такое идентификатор пользователя.)   -  person Marc Rochkind    schedule 08.10.2014
comment
Согласитесь, есть несколько терминов, которые нужно разделить. Отредактировал пост для ясности. В первой ссылке в посте указан client_id, он нужен для указания аудитории в id_token. Думаю, понятно, что мне нужен id_token, который можно проверить при добавлении к googleapis.com. /oauth2/v1/tokeninfo?id_token=   -  person chris    schedule 09.10.2014
comment
Вы пытались добавить openid к областям? Обычно это необходимая подсказка, чтобы перевести сервер в режим OpenID Connect и выдать токен идентификатора.   -  person Pieter Ennes    schedule 23.01.2018


Ответы (3)


Вчера я столкнулся с той же проблемой, и, поскольку я нашел решение, я мог бы поделиться им, так как это было не так очевидно. Насколько я знаю, Google не предоставляет прямого и документированного способа сделать это, но вы можете использовать функцию chrome.identity.launchWebAuthFlow().

Сначала вы должны создать учетные данные веб-приложения в консоли Google и добавить следующий 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);
        }
    }
);

Документацию по API Google OAuth2 (для OpenID Connect) можно найти здесь: https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters

PS: Если вам не нужен раздел oauth2 в вашем манифесте. Вы можете смело опустить его и предоставить идентификаторы и области видимости только в коде.

РЕДАКТИРОВАТЬ: Для тех, кто заинтересован, вам не нужен API идентификации. Вы даже можете получить доступ к токену, используя небольшой трюк с API вкладок. Код немного длиннее, но у вас лучше сообщения об ошибках и управление. Помните, что в следующем примере вам необходимо создать учетные данные Chrome App.

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});
});
person Piotr Sobiech    schedule 13.09.2015
comment
Привет Петр. Я пробовал ваше решение, но получаю сообщение об ошибке Не удалось загрузить страницу авторизации. Я делаю именно то, что вы делаете, с теми же областями в манифесте. - person Egidio Caprino; 12.06.2016
comment
Привет @Aegidius, ты понял это? У меня такая же проблема. Спасибо. - person rsb; 21.03.2017
comment
@Aegidius, то же самое здесь, не уверен, что этот метод все еще действителен? - person seesoe; 06.10.2017
comment
Здесь необходимо внести два изменения. 1) Новая база конечной точки — https://accounts.google.com/o/oauth2/v2/auth 2) nonce — это обязательный параметр URL-адреса для URL-адреса аутентификации, поэтому добавьте что-то вроде &nonce=<your nonce value> - person dadykhoff; 07.02.2019
comment
id_token рекомендуется при передаче информации о пользователе из расширения на внутренний сервер (см. здесь: developers.google.com/identity/sign-in/web/backend-auth). Однако я не могу заставить это работать, так как я получаю сообщение Invalid Redirect: домен должен быть добавлен в список авторизованных доменов перед отправкой. при попытке создать веб-клиент OAuth из консоли учетных данных. Добавление URL-адреса расширения в авторизованные домены не работает, поскольку домены должны быть частными доменами верхнего уровня. Похоже на Уловку-22... не знаю, что делать. - person chas; 04.05.2019
comment
На самом деле мне удалось взломать вкладки (спасибо Петру), но этот UX не будет работать для моих целей. - person chas; 04.05.2019
comment
Фоновая страница, открывающая новую вкладку, сработала, спасибо! Похоже, мой page_action не смог перенаправить себя на страницу входа - person neaumusic; 01.01.2020
comment
это очень хорошо решает мою проблему!! повторяя @dadykhoff, URL-адрес должен быть обновлен, и нам нужно добавить одноразовый номер - person rendybjunior; 20.03.2020

Во-первых, я предполагаю, что в вашем фрагменте manifest.json вы не имеете в виду, что ваш client_id буквально "<chrome-app-client-id>.apps.googleusercontent.com. Это должно быть что-то вроде 9414861317621.apps.googleusercontent.com — что-то, что вы получили из консоли разработчика или с любого другого сайта Google, который вы использовали для регистрации приложения.

Предполагая, что с вышеприведенным все в порядке, и у вас есть права client_id и права области действия, вы получаете так называемый «токен доступа OAuth2» с вызовом chrome.identity.getAuthToken. Поскольку вы не показываете нам код 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 — это передаваемый заголовок. (Извините, у меня нет времени разрабатывать отдельный код только для этого ответа.)

Я надеюсь, что вышеизложенное полезно.

person Marc Rochkind    schedule 09.10.2014
comment
Спасибо за попытку помочь, но это не ответ на мой вопрос. В моем вопросе в строке 3 я говорю, что знаю, как получить access_token (я включил это, чтобы избежать ответов, объясняющих, как его получить). Я пытаюсь получить id_token (токен, который можно проверить при добавлении к этому URL-адресу: googleapis.com/oauth2/v1/tokeninfo?id_token=) - person chris; 15.10.2014
comment
Вы когда-нибудь догадывались об этом? Я также пытаюсь сделать то же самое. Спасибо. - person rsb; 21.03.2017
comment
все еще борюсь с этим :/ - person kidCoder; 29.10.2017

Я думаю, это зависит от того, зачем нужен идентификатор токена, но в моем случае access_token было достаточно для авторизации пользователя - путем извлечения информации о пользователе из https://www.googleapis.com/oauth2/v2/userinfo?alt=json (с заголовком авторизации = access_token).

person ego    schedule 02.06.2018
comment
id_token можно передать серверу, говоря: «Да, я — этот пользователь» — Google утверждает, что это так, и что я намереваюсь использовать это одобрение для вашего приложения (проект client_id), и вы можете проверить утверждение, используя общедоступный .well- Google. известный сертификат - person neaumusic; 01.01.2020