我正在尝试获得一个访问令牌,这样我就可以使用。
看来这是我唯一能做到的办法。我使用的是Cloudflare工作人员,因为这需要在浏览器上运行,所以我认为一些库可以方便我无法使用的工作。
我在实习,给我这个任务的人给我寄了这份文件。
{
"type": "service_account",
"project_id": "...",
"private_key_id": "...",
"private_key": "-----BEGIN PRIVATE KEY-----\nMII...NF0=\n-----END PRIVATE KEY-----\n",
"client_email": "...",
"client_id": "...",
"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_x509_cert_url": "..."
}
我已经可以使用该文件创建音频,方法是将文件的路径作为特定的环境变量,然后使用gcloud
CLI工具打印访问令牌,然后使用它。但我不知道记号变了。
现在,我正在尝试使用JWT令牌。
这是我为测试JWT而创建的一个文件。
它创建JWT,但是当我执行POST请求以在响应中获取access_token
时,我只得到id_token
。
const jwt = require("jsonwebtoken");
const credentials = require("./credentials.json");
const corsHeaders = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Headers": "Authorization",
"Access-Control-Allow-Credentials" : true,
}
async function main() {
const JWTToken = jwt.sign({
"iss": credentials.client_email,
"sub": credentials.client_email,
"scope": "https://texttospeech.googleapis.com/$discovery/rest?version=v1",
//"aud": credentials.token_uri,
"aud": "https://www.googleapis.com/oauth2/v4/token",
"exp": Math.floor(+new Date() / 1000) + 60 * 45,
"iat": Math.floor(+new Date() / 1000),
}, credentials.private_key, {
"algorithm": "RS256",
"header": {
"kid": credentials.private_key_id,
"typ": "JWT",
"alg": "RS256",
}
});
const JWTBody = new URLSearchParams();
JWTBody.append("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
JWTBody.append("assertion", JWTToken);
let JWTResponse;
try {
//JWTResponse = await fetch("https://oauth2.googleapis.com/token", {
JWTResponse = await fetch("https://www.googleapis.com/oauth2/v4/token", {
method: "POST",
body: JWTBody,
});
} catch (e) {
console.error(e);
return new Response(`${e.name}: ${e.message}`, {
status: 500,
statusText: "Internal Server Error",
headers: new Headers(corsHeaders),
});
}
let JWTResponseBody;
if (JWTResponse.ok) {
JWTResponseBody = await JWTResponse.json();
console.log("JWT", JWTResponseBody);
console.log("JWT ACCESS_TOKEN", JWTResponseBody["access_token"]);
} else {
console.error("HTTP status code: ", JWTResponse.status, JWTResponse.statusText, JWTResponse);
return new Response("HTTP status code: " + JWTResponse.status + JWTResponse.statusText, {
status: 500,
statusText: "Internal Server Error",
headers: new Headers(corsHeaders),
});
}
const TTSGoogleAPIsEndpoint = new URL("https://texttospeech.googleapis.com");
const TTSRESTResources = {
synthesize: new URL("/v1/text:synthesize", TTSGoogleAPIsEndpoint),
list: new URL("/v1/voices", TTSGoogleAPIsEndpoint),
};
let response;
try {
response = await fetch(TTSRESTResources.synthesize, {
method: "POST",
headers: new Headers({
"Authorization": `Bearer ${JWTResponseBody["access_token"]}`,
"Content-Type": "application/json; charset=utf-8",
}),
body: JSON.stringify({
"audioConfig": {
"audioEncoding": "LINEAR16",
"pitch": 0,
"speakingRate": 1
},
"input": {
"ssml": "<speak> <emphasis level=\"strong\">To be</emphasis> <break time=\"200ms\"/> or not to be? </speak>"
},
"voice": {
"languageCode": "en-US",
"name": "en-US-Standard-A"
}
}),
});
} catch (e) {
console.error(e);
return new Response(`${e.name}: ${e.message}`, {
status: 500,
statusText: "Internal Server Error",
headers: new Headers(corsHeaders),
});
}
if (response.ok) {
const audio = await response.json();
console.log(audio);
} else {
console.error("HTTP status code: ", response.status, response.statusText);
console.log(response.headers.get("WWW-Authenticate"));
return new Response("HTTP status code: " + response.status + response.statusText, {
status: 500,
statusText: "Internal Server Error",
headers: new Headers(corsHeaders),
});
}
}
main();
当我运行代码时,它会打印如下:
(node:53185) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
JWT {
id_token: 'eyJh ... THE ID_TOKEN ... BSZw'
}
JWT ACCESS_TOKEN undefined
HTTP status code: 401 Unauthorized
Bearer realm="https://accounts.google.com/", error="invalid_token"
我已经在控制台上记录了JWTToken
,并在邮递员上完成了邮件请求。它给出了相同的响应,只有id_token
。
我认为问题可能是JWT的有效负载内容,我不知道它的作用域是否正确,如果我需要使用https://www.googleapis.com/oauth2/v4/token
URL或aud
凭据中的范围。对于我需要用于fetch()
的URL也是一样的。但我想我测试了所有的网址可能性,它从来没有给access_token
。
谢谢
解决方案
JWT有效负载上的作用域是错误的。它必须是"scope": "https://www.googleapis.com/auth/cloud-platform",
。
约翰·汉利回答。
发布于 2022-07-05 06:32:04
您的代码指定了一个不存在的OAuth作用域(格式完全错误)。
async function main() {
const JWTToken = jwt.sign({
"iss": credentials.client_email,
"sub": credentials.client_email,
"scope": "https://www.googleapis.com/auth/cloud-platform",
...
URI https://www.googleapis.com/oauth2/v4/token
是正确的。您还可以使用auth_uri
:https://accounts.google.com/o/oauth2/auth
中的值。
这将解决JWT访问令牌的问题。如果你有进一步的问题,文本到语音API,张贴一个新的问题。
https://stackoverflow.com/questions/72862609
复制相似问题