验证来自Google Chat POST请求的JWT

时间:2019-04-15 21:50:03

标签: node.js google-api jwt

我有一个NodeJS机器人,它使用HTTPs端点连接到Google Chat。我正在使用快递来接收请求。我需要验证所有请求均来自Google,并希望使用Google随请求发送的承载令牌来执行此操作。

我的问题是我正在努力寻找一种方法来验证令牌。

我已经捕获了令牌,并尝试对https://oauth2.googleapis.com/tokeninfo?id_token=ey ...(其中ey ...是令牌的开头)进行GET reuqes。

哪个返回:

    "error": "invalid_token",
    "error_description": "Invalid Value"
}

我尝试了Google的建议:

var token = req.headers.authorization.split(/[ ]+/);
client.verifyIdToken({
    idToken: token[1],
    audience: JSON.parse(process.env.valid_client_ids)
}).then((ticket) => {
    gchatHandler.handleGChat(req.body, res);
}).catch(console.error);

并出现以下错误:

错误:找不到信封的pem:{“ alg”:“ RS256”,“ kid”:“ d ... 1”,“ typ”:“ JWT”}

有什么想法我应该从这里出发吗?

编辑:https://www.googleapis.com/service_accounts/v1/metadata/x509/chat@system.gserviceaccount.com发现了这一点,正在研究如何使用它。那孩子匹配我得到的那个。

2 个答案:

答案 0 :(得分:0)

最终解决了。

您需要点击:https://www.googleapis.com/service_accounts/v1/metadata/x509/chat@system.gserviceaccount.com以获取一个JSON文件,其中包含链接到其KID的密钥。

然后,当请求到达时,使用jsonwebtoken(NPM)解码令牌并从标头中提取KID。

使用KID在上述网站的响应中找到匹配的公钥,然后使用验证功能确保令牌与公钥匹配。

您还需要传递观众和发行者的选项进行验证,以确认这是您攻击机器人的特定服务帐户。

答案 1 :(得分:0)

上述解决方案可能适用于 Google Chat,但根据我的经验,Google 服务(例如 Google Tasks)使用 OIDC 令牌,可以使用 verifyIdToken 函数进行验证。

在此处添加我的解决方案,因为您的问题/答案是我能找到的最接近我的问题的问题

因此,如果您需要使用自己的代码签署请求

在客户端,使用 OIDC 令牌发送请求

import {URL} from 'url';
import {GoogleAuth} from 'google-auth-library'; 

// will use default auth or GOOGLE_APPLICATION_CREDENTIALS path to SA file
// you must validate email of this identity on the server!
const auth = new GoogleAuth({});

export const request = async ({url, ...options}) => {
  const targetAudience = new URL(url as string).origin;
  const client = await auth.getIdTokenClient(targetAudience);
  return await client.request({...options, url});
};

await request({ url: 'https://my-domain.com/endpoint1', method: 'POST', data: {} })

在服务器上,验证 OIDC(Id 令牌)


const auth = new OAuth2Client();

const audience = 'https://my-domain.com';


// to validate
const token = req.headers.authorization.split(/[ ]+/)[1];
const ticket = await auth.verifyIdToken({idToken: token, audience });

if (ticket.getPayload().email !== SA_EMAIL) {
 throw new Error('request was signed with different SA');
}
// all good

详细了解Google OpenID Connect Tokens