You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Google Cloud获取OAuth2 Token时提示账号不存在的问题排查

Google Cloud OAuth2 Token请求报错:账号不存在

请求OAuth2 Token时返回如下错误:

Status Code: HTTP/1.1 400 Bad Request
Response: {"error":"invalid_grant","error_description":"Invalid grant: account not found"}

我使用拥有Token生成权限的服务账号,通过以下代码尝试获取Token,采用Apache HttpComponents处理网络请求、io.jsonwebtoken构建JWT。由于对这些库和Java开发不太熟悉,想请教代码中是否存在明显功能性问题:

import io.jsonwebtoken.*
import io.jsonwebtoken.security.Keys;
import org.apache.commons.codec.binary.Base64
import org.apache.http.client.methods.*
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import java.security.Key;
import java.security.PrivateKey
import java.util.Base64
import java.util.Base64.Decoder
import java.nio.charset.StandardCharsets
import java.security.interfaces.*
import java.security.KeyFactory
import java.security.NoSuchAlgorithmException
import java.security.spec.PKCS8EncodedKeySpec
import java.security.Key;

iss = "serviceacct@project.iam.gserviceaccount.com" // svc account email 
scope = "https://www.googleapis.com/auth/compute.readonly" // A space-delimited list of the permissions that the application requests.
aud = "https://oauth2.googleapis.com/token" // ALWAYS

def iat = (System.currentTimeMillis() / 1000).trunc()
// //  The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970.
def exp = (System.currentTimeMillis() / 1000 + 1200).trunc()
//20 minutes from now // The expiration time of the assertion, specified as seconds since 00:00:00 UTC, January 1, 1970. This value has a maximum of 1 hour after the issued time.

//JWT Payload 
String jsonString = """{"typ":"${iss}",
                        "scope":"${scope}",
                        "aud":"${aud}",
                        "exp":"${exp}",
                        "iat":"${iat}"}""";

// Formatting key
StringBuilder pkcs8Lines = new StringBuilder();
BufferedReader rdr = new BufferedReader(new StringReader(BASEKEY));
String line;
while ((line = rdr.readLine()) != null) {
    pkcs8Lines.append(line);
}
// Cleaning key 
String pkcs8Pem = pkcs8Lines.toString();
pkcs8Pem = pkcs8Pem.replace("-----BEGIN PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replace("-----END PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replaceAll("\\s+","");
// Decoding key
byte[] valueDecoded = Base64.decodeBase64(pkcs8Pem);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(valueDecoded);
KeyFactory rsaFact = KeyFactory.getInstance("RSA");
RSAPrivateKey key = (RSAPrivateKey) rsaFact.generatePrivate(keySpec);

// Generate Token
String jwt = Jwts.builder()
        //JWT Header
    .setHeaderParam("alg","RS256")
    .setHeaderParam("typ","JWT")
    .setPayload(jsonString)
    .signWith(SignatureAlgorithm.RS256, key)
    .compact();

def httpClient = HttpClientBuilder.create().build()
def httpPost = new HttpPost(aud)
String bodystring = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion="+"${jwt}"
String encodedParams = URLEncoder.encode(bodystring, StandardCharsets.UTF_8); // Encode
StringEntity entity = new StringEntity(bodystring)

httpPost.setEntity(entity);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded")

def response = httpClient.execute(httpPost)

//debug
String statusCode = response.getStatusLine() //.getStatusCode();
String content = response.getEntity().getContent().getText() //.getStatusCode();
System.out.println("Status Code: " + statusCode);
System.out.println("Response: " + content);

我曾按照Google OAuth2服务账号认证文档调整JWT payload,但问题未解决。另外发现:即使设置请求Content-Type为url编码,调试时entity的Content-Type仍显示为text/plain; charset=ISO-8859-1,后续成功设置entity的Content-Type,但错误依然存在。

内容的提问来源于stack exchange,提问作者Scott MacDonald

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:02:15