如何从 id_token Google Javascript API 客户端 (GAPI) 检索电子邮件地址

How to retrieve email address from id_token Google Javascript API client (GAPI)

我有一个带有 Firebase 后端的 SPA,并且集成了 Google 日历访问。

为了能够授权用户使用 his/her Google 日历,我正在使用 gapi.auth2.authorize(params, callback) 方法。 (这与常规的 gapi.auth2.initsignIn 流程相反,因为我的用户可以 link 多个日历帐户)

Docs: gapi.auth2.authorize

我遇到的问题:

有时 return 从 authorize 编辑的 id_token 包含电子邮件地址,有时则不包含。

return编辑的id_token是一个长字符串,可以在前端使用JavaScript函数读取,如下所示:

    function parseJwt (token) {
      let base64Url = token.split('.')[1]
      let base64 = base64Url.replace('-', '+').replace('_', '/')
      return JSON.parse(window.atob(base64))
    }

当我解析 id_token 时,我需要一个包含 email 地址的对象。但是有时它根本不包括 email 属性.... 我如何使用 JavaScript 从这个 id_token 中检索用户的 google 日历电子邮件地址,以便将其保存到用户的 firestore 数据库中?

解析 id_token 时的预期结果示例:

意外结果示例(无电子邮件):

可能原因:

我认为这可能与未 return 发送电子邮件的帐户是 Google G-Suite 帐户有关?那些做 return 电子邮件的是普通的 gmail 帐户?但是我不知道解决方法。

PS:
我为 return 用户重新授权的流程是只使用相同的 gapi.auth2.authorize 但使用 {prompt: 'none', login_hint: 'emailaddress'} 并填写用户保存的电子邮件地址。这很好用。

如果您想使用 gapi.auth2.authorize 授权 JavaScript 客户端,但还需要用户授权的电子邮件地址,请务必将 email 包含在gapi.auth2.authorize(params, callback) 参数的范围!!

使用JavaScript gapi授权Google日历的正确示例:

步骤 1.
包含在主要 HTML head:

<script type=text/javascript src="https://apis.google.com/js/api.js" async defer=defer></script>

第2步
(一次)加载客户端:
window.gapi.load('client', callbackFunction)
重要:只加载客户端!

步骤 3.
(一次)初始化客户端以使用日历 API。
重要提示:仅包含发现文档!

let calDocs = {
    discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest']
}
window.gapi.client.init(calDocs)
    .then(_ => {
      console.log('Calendar client initialised')
    })
  })
},

步骤 4.
(一次)授权 gapi 客户端进行 API 调用
gapi.auth2.authorize(params, callbackFunction)
重要提示:范围是一个带空格的字符串!在范围内包括电子邮件。不要在此处包含发现文档!

params = {
    client_id: clientId,
    scope: 'https://www.googleapis.com/auth/calendar email',
    response_type: 'permission id_token'
}

您可以在任何带有额外参数的 API 调用之前重复 gapi.auth2.authorize{prompt: 'none', login_hint: 'emailaddress'} 以刷新用户的访问令牌。如果用户已经为您的域授权一次,这将不会向用户显示任何提示。