正如 Matthew 所说,用于获取刷新令牌的客户端 ID 的项目应与 IAP 客户端 ID 的项目匹配。Gcloud 使用在path_to/google-cloud-sdk/lib/googlecloudsdk/api_lib/auth/util.py
默认凭据 (DEFAULT_CREDENTIALS_DEFAULT_CLIENT_ID
和DEFAULT_CREDENTIALS_DEFAULT_CLIENT_SECRET
) 中定义的客户端 ID 和密码。因此,您不能在google.auth.default()
不util.py
更改的情况下使用刷新令牌,因为尝试获取 ID 令牌将失败:
{
"error": "invalid_audience",
"error_description": "The audience client and the client need to be in the same project."
}
您的选择是:
- 根据 Matthew 的回复/文档获取刷新令牌(缓存它以避免每次都需要用户授权)和 ID 令牌。
- 修补 gcloud util.py 中存在的客户端 ID 和密钥(可能会随着 gcloud 更新而更改)。
两个选项的示例代码:
import google.auth
import requests
import json
from webbrowser import open_new_tab
from time import sleep
# use gcloud app default credentials if gcloud's util.py is patched
def id_token_from_default_creds(audience):
cred, proj = google.auth.default()
# data necessary for ID token
client_id = cred.client_id
client_secret= cred.client_secret
refresh_token = str(cred.refresh_token)
return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)
def id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):
oauth_token_base_URL = "https://www.googleapis.com/oauth2/v4/token"
payload = {"client_id": client_id, "client_secret": client_secret,
"refresh_token": refresh_token, "grant_type": "refresh_token",
"audience": audience}
res = requests.post(oauth_token_base_URL, data=payload)
return (str(json.loads(res.text)[u"id_token"]))
# obtain ID token for provided Client ID: get authorization code -> exchange for refresh token -> obtain and return ID token
def id_token_from_client_id(client_id, client_secret, audience):
auth_code = get_auth_code(client_id)
refresh_token = get_refresh_token_from_code(auth_code, client_id, client_secret)
return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)
def get_auth_code(client_id):
auth_url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob"%client_id
open_new_tab(auth_url)
sleep(1)
return raw_input("Authorization code: ")
def get_refresh_token_from_code(auth_code, client_id, client_secret):
oauth_token_base_URL = 'https://www.googleapis.com/oauth2/v4/token'
payload = {"code": auth_code, "client_id": client_id, "client_secret": client_secret,
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "grant_type": "authorization_code"}
res = requests.post(oauth_token_base_URL, data=payload)
return (str(json.loads(res.text)[u"refresh_token"]))
print("ID token from client ID: %s" % id_token_from_client_id("<Other client ID>", "<Other client secret>", "<IAP Client ID>")) # other client ID should be from the same project as IAP Client ID
print("ID token from \"default\" credentials: %s" % id_token_from_default_creds("<IAP Client ID>"))