Google Tasks身份验证:处理嵌入式设备的刷新令牌

huangapple go评论62阅读模式
英文:

Google Tasks Authentication: Handle refresh tokens for Embedded Devices

问题

我正在为一个个人嵌入式设备(Visionect电子墨水显示屏)开发应用,该设备可以运行一些Node.js代码来显示我的Google任务。它运行良好,但访问令牌定期过期。我应该如何处理令牌过期?当然,我不能在这个电子墨水显示屏上显示登录屏幕。我如何永久拥有可以一直工作,直到用户(在这种情况下只有一个用户 - 我)撤销访问令牌的代码?

我查看了这个答案,但我不确定它是否回答了我的问题:https://stackoverflow.com/questions/53786782/google-api-authentication-tasks-api/53787724#53787724

以下是我的代码:

/*
credentials.json:

{
  "installed": {
    "client_id": "XXXXXXX.apps.googleusercontent.com",
    "project_id": "XXXXXXX",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "XXXXXXX",
    "redirect_uris": [
      "http://localhost"
    ]
  }
}
*/

import fs from 'fs'
import path from 'path'
import process from 'process'
import {authenticate} from '@google-cloud/local-auth'

const SCOPES = ['https://www.googleapis.com/auth/tasks.readonly']
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json')

let myauth = undefined

if (!myauth) {
await authenticate({scopes: SCOPES, keyfilePath: CREDENTIALS_PATH})
  .then(client => {
    const keys = JSON.parse(fs.readFileSync(CREDENTIALS_PATH))
    const key = keys.installed || keys.web
    myauth = {
      type: 'authorized_user',
      client_id: key.client_id,
      client_secret: key.client_secret,
      refresh_token: client.credentials.refresh_token,
    }
    console.log(myauth)
  })
}

import {google} from 'googleapis'

google.options({auth: google.auth.fromJSON({
      type: "authorized_user",
      client_id: myauth.client_id
      client_secret: myauth.client_secret,
      refresh_token: myauth.refresh_token
 
})})


// Method to fetch tasks from last n days
const tasks = (maxDueDays) => {
  const fetchTaskList = (taskList) => taskApi.tasks
    .list({
      tasklist: taskList.id,
      showCompleted: false,
      dueMax: dayjs().add(maxDueDays, 'days').format()
    })
    .then(res => res.data.items.map(task => Object.assign(task, {taskList: taskList.title})))

  return taskApi
    .tasklists.list()
    .then(res => Promise.all(res.data.items.map(fetchTaskList)))
    .then(tasks => tasks.flat())
}

tasks(7).then(res => console.log(res))

一段时间后(我每小时轮询一次),我经常会收到以下错误消息:

ERROR 400: {
error: 'invalid_grant',
error_description: 'Token has been expired or revoked.'
}

以下是其他GitHub问题,其中人们遇到了我的问题:

Google是否提供“个人API密钥”,让我可以绕过OAuth流程直接读取自己的数据,因为这个应用程序只用于个人使用?如果不是,是否有一种编程方式来处理令牌过期,而不涉及打开浏览器,因为这在运行在无头嵌入式设备上?Google的示例代码教程似乎并没有处理令牌过期!

英文:

I am developing for a personal embedded device (the Visionect e-ink display) that can run some node.js code to display tasks from my Google Tasks. It works fine but the token expires every so often. How do I handle the token expiry? I cannot show the login screen ofcourse on this e-ink display. How can I permanently have code that works till the user (in this case there is only 1 user - me) revokes the access token?

I looked at this answer but I am not sure it answers my question: https://stackoverflow.com/questions/53786782/google-api-authentication-tasks-api/53787724#53787724

Here is my code:

/*
credentials.json:

{
  "installed": {
    "client_id": "XXXXXXX.apps.googleusercontent.com",
    "project_id": "XXXXXXX",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "XXXXXXX",
    "redirect_uris": [
      "http://localhost"
    ]
  }
}
*/

import fs from 'fs'
import path from 'path'
import process from 'process'
import {authenticate} from '@google-cloud/local-auth'

const SCOPES = ['https://www.googleapis.com/auth/tasks.readonly']
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json')

let myauth = undefined

if (!myauth) {
await authenticate({scopes: SCOPES, keyfilePath: CREDENTIALS_PATH})
  .then(client => {
    const keys = JSON.parse(fs.readFileSync(CREDENTIALS_PATH))
    const key = keys.installed || keys.web
    myauth = {
      type: 'authorized_user',
      client_id: key.client_id,
      client_secret: key.client_secret,
      refresh_token: client.credentials.refresh_token,
    }
    console.log(myauth)
  })
}

import {google} from 'googleapis'

google.options({auth: google.auth.fromJSON({
      type: "authorized_user",
      client_id: myauth.client_id
      client_secret: myauth.client_secret,
      refresh_token: myauth.refresh_token
 
)})


// Method to fetch tasks from last n days
const tasks = (maxDueDays) => {
  const fetchTaskList = (taskList) => taskApi.tasks
    .list({
      tasklist: taskList.id,
      showCompleted: false,
      dueMax: dayjs().add(maxDueDays, 'days').format()
    })
    .then(res => res.data.items.map(task => Object.assign(task, {taskList: taskList.title})))

  return taskApi
    .tasklists.list()
    .then(res => Promise.all(res.data.items.map(fetchTaskList)))
    .then(tasks => tasks.flat())
}

tasks(7).then(res => console.log(res))

After a bit (I poll once a hour), I often get:

ERROR 400: {
error: 'invalid_grant',
error_description: 'Token has been expired or revoked.'
}

Here are some other Github issues where people encountered my problem:

Does Google provide a "personal API key" which let's me just read my own data bypassing the oauth dance since this app is only intended for my personal use? If not, is there a programmatic way to handle token expiry which does not involve opening a browser since this is running on an embedded headless device? Google's own sample code tutorial does not really handle token expiry!

答案1

得分: 1

将您的应用设置为Google Cloud控制台中的生产模式,位于oauth2同意屏幕下,您的刷新令牌将不会过期。

英文:

Set your app to production in google cloud console under the oauth2 consent screen and your refresh token will stop expiring

huangapple
  • 本文由 发表于 2023年6月8日 01:35:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76425806.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定