Могу ли я получить согласованное значение "iss" для идентификатора Google OpenIDConnect id_token?

Я использую аутентификацию OpenIDConnect от Google и хочу проверить JWT id_token вернулся из Google. Тем не менее, документация не соответствует тому, какое значение Google возвращает для iss (эмитент) претензия в идентификационном токене.

На одной странице написано: "iss: всегда accounts.google.com", а на другой странице указано "значение iss в токене идентификатора равно accounts.google.com или же https://accounts.google.com"и комментарий в примере кода дополнительно объясняет:

// If you retrieved the token on Android using the Play Services 8.3 API or newer, set
// the issuer to "https://accounts.google.com". Otherwise, set the issuer to
// "accounts.google.com". If you need to verify tokens from multiple sources, build
// a GoogleIdTokenVerifier for each issuer and try them both.

У меня есть приложение на стороне сервера, а не приложение для Android, поэтому я не использую Play Services.

Чтобы еще больше мутить воду, сама спецификация OpenIDConnect содержит примечание, которое:

Разработчики могут пожелать знать, что на момент написания этой статьи развернутые Google реализации OpenID Connect выдают токены идентификаторов, в которых отсутствует обязательный префикс схемы https: // в значении претензии iss (эмитента). Поэтому реализации проверяющей стороны, желающие работать с Google, должны иметь код для обхода этого до тех пор, пока их реализация не будет обновлена. Любой такой обходной код должен быть написан таким образом, чтобы в этот момент он не ломался. Google добавляет отсутствующий префикс к значениям их эмитента.

Этот документ датирован 8 ноября 2014 года. С тех пор Google стандартизировал iss значение, или мне действительно нужно проверить их обоих? Комментарий выше, кажется, указывает, что только Play Services >=8.3 получает iss с https://и везде значение будет просто accounts.google.com, Это правда?

2 ответа

Вы должны проверить обе возможности. Это то, что сработало для меня...

Расшифруйте токен, чтобы получить эмитента. Если эмитент не равен ни одному из https://accounts.google.com или же accounts.google.com Вы можете остановиться там. Это неверный токен.

Если эмитент равен какой-либо из приведенных выше строк Google, передайте это же декодированное значение эмитента на этап проверки.

Ниже приведена реализация, которую я написал в JavaScript для некоторого промежуточного программного обеспечения Node.js Express:

function authorize(req, res, next) {
    try {
        var token       = req.headers.authorization;
        var decoded     = jwt.decode(token, { complete: true });
        var keyID       = decoded.header.kid;
        var algorithm   = decoded.header.alg;
        var pem         = getPem(keyID);
        var iss         = decoded.payload.iss;

        if (iss === 'accounts.google.com' || iss === 'https://accounts.google.com') {
            var options = {
                audience: CLIENT_ID,
                issuer: iss,
                algorithms: [algorithm]
            }

            jwt.verify(token, pem, options, function(err) {
                if (err) {
                    res.writeHead(401);
                    res.end();
                } else {
                    next();
                }
            });            

        } else {
            res.writeHead(401);
            res.end();
        }
    } catch (err) {
        res.writeHead(401);
        res.end();
    }
}

Обратите внимание, что эта функция использует jsonwebtoken а также jwk-to-pem узловые модули. Я опустил детали getPem функция, которая в конечном итоге преобразует веб-ключ json в формат pem.

Для начала, я определенно согласен с тем, что документация Google - мрачный бизнес.

Существует несколько способов проверить целостность идентификатора токена на стороне сервера (кстати, это страница, которую вы ищете):

  1. "Вручную" - постоянно загружать открытые ключи Google, проверять подпись, а затем каждое поле, включая iss один; главное преимущество (хотя и небольшое, на мой взгляд), которое я вижу здесь, заключается в том, что вы можете минимизировать количество запросов, отправляемых в Google).
  2. "Автоматически" - сделать GET на конечной точке Google, чтобы проверить этот токен - безусловно, самое простое:https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
  3. Использование клиентской библиотеки Google API - накладные расходы могут не стоить того, C# не имеет официального и т. д.

Я предлагаю вам перейти ко второму варианту и позволить Google беспокоиться об алгоритме проверки.