如果您的應用程式可讓使用者透過 Google 登入帳戶,您可以監聽及回應跨帳戶保護服務提供的安全性事件通知,藉此提升這些共用帳戶的安全性。
這類通知是要通知您,使用者的 Google 帳戶有重大變更。使用這項服務時,您的帳戶有時會受到安全性方面的影響。舉例來說,如果使用者的 Google 帳戶遭到入侵,他可能會透過電子郵件電子郵件帳戶或單一登入,透過使用者帳戶入侵使用者的帳戶。
為協助您降低這類事件的風險,Google 會傳遞稱為「安全事件權杖」的服務物件。這些權杖提供的資訊非常少,包括安全性事件的發生時間、發生事件的 ID,以及受影響使用者的 ID,不過您可以利用這些憑證來採取適當行動。舉例來說,如果使用者的 Google 帳戶遭到入侵,您可以暫時為該使用者停用「使用 Google 帳戶登入」功能,避免帳戶救援電子郵件傳送至使用者的 Gmail 地址。
跨帳戶防護功能是以 OpenID 標準開發而成,並以 OpenID Foundation 開發而成。
總覽
如要搭配應用程式或服務使用跨帳戶防護功能,您必須完成以下工作:
在 API Console中設定專案。
建立事件接收器端點,讓 Google 傳送安全性事件權杖。此端點負責驗證收到的權杖,然後以您選擇的方式回應安全性事件。
向 Google 註冊端點,即可開始接收安全性事件權杖。
必要條件
只有當您授予服務存取設定檔資訊或電子郵件地址的 Google 使用者,才會收到安全性事件權杖。您可以要求 profile
或 email
範圍,藉此取得這項權限。根據預設,新版「使用 Google 帳戶登入」或舊版 Google 登入 SDK 要求這些範圍,但如果您並未使用預設設定,或直接存取 Google 的 OpenID Connect 端點,請務必至少要求其中一個範圍。
在 API Console中設定專案
在開始接收安全性事件權杖前,您必須先建立服務帳戶,並在API Console 專案中啟用 RISC API。您必須在應用程式中使用與存取 Google 服務 (如 Google 登入) 相同的API Console 專案。
如何建立服務帳戶:
開啟 API Console Credentials page。當系統顯示提示時,請選擇在應用程式中存取 Google 服務時使用的API Console專案。
依序點選「建立憑證」>「服務帳戶」。
按照這些操作說明,透過 RISC 設定管理員角色 (
roles/riscconfigs.admin
) 建立新的服務帳戶。為新建立的服務帳戶建立金鑰。選擇 JSON 金鑰類型,然後按一下「Create」(建立)。金鑰建立完畢後,您必須下載 JSON 檔案,其中包含您的服務帳戶憑證。請將這個檔案存放在安全的位置,但方便事件監聽器端點存取。
在專案的「憑證」頁面時,請記下您用來登入 Google 或 Google 登入工具 (舊版) 的用戶端 ID。通常,每個支援的平台都有用戶端 ID。您必須使用這些用戶端 ID 來驗證安全性事件權杖,詳情請見下一節。
啟用 RISC API:
在API Console中開啟 RISC API 頁面。確認已選取用於存取 Google 服務的專案。
閱讀 RISC 條款,確認您瞭解相關規定。
如果您要為機構擁有的專案啟用 API,請確認您是否有權將貴機構繫結至 RISC 條款。
除非您同意 RISC 條款,否則請勿點選「啟用」。
建立事件接收器端點
如要接收 Google 的安全性事件通知,您必須建立處理 HTTPS POST 要求的 HTTPS 端點。註冊這個端點 (請見下方說明) 之後,Google 就會開始將加密編譯的權杖字串張貼至端點,稱為安全性事件權杖。安全性事件權杖是已簽署的 JWT,其中包含單一安全性相關事件的相關資訊。
針對收到端點的每個安全性事件權杖,請先驗證並解碼權杖,然後視情況處理服務適用的安全性事件。解碼之前,必須驗證事件符記,以避免惡意人士惡意攻擊。以下各節將說明這些工作:
1. 解碼並驗證安全性事件權杖
由於安全性事件符記是特定類型的 JWT,因此您可以使用任何 JWT 程式庫 (例如 jwt.io 中列出的程式庫) 來解碼及驗證權杖。無論您使用哪個程式庫,權杖的驗證碼都必須執行下列步驟:
- 從 Google 的 RISC 設定文件取得跨帳戶防護核發機構 ID (
issuer
) 和簽署金鑰憑證 URI (jwks_uri
)。詳情請參閱https://accounts.google.com/.well-known/risc-configuration
。 - 使用您偏好的 JWT 程式庫,從安全性事件權杖的標頭取得簽署金鑰 ID。
- 從 Google 的簽署金鑰憑證文件,取得您在上一個步驟中取得的金鑰 ID。如果文件沒有包含您要尋找 ID 的金鑰,可能是因為安全性事件權杖無效,且端點應傳回 HTTP 錯誤 400。
- 使用您選擇的 JWT 程式庫來驗證下列項目:
- 安全性事件權杖是以您在上一個步驟中取得的公開金鑰簽署。
- 權杖的
aud
憑證是應用程式的其中一個用戶端 ID。 - 權杖的
iss
憑證與您在 RISC 探索文件中獲得的核發機構 ID 相符。請注意,您不需要驗證權杖的到期日 (exp
),因為安全性事件權杖代表歷史事件,因此並不會過期。
例如:
Java
使用 java-jwt 和 jwks-rsa-java:
public DecodedJWT validateSecurityEventToken(String token) {
DecodedJWT jwt = null;
try {
// In a real implementation, get these values from
// https://accounts.google.com/.well-known/risc-configuration
String issuer = "accounts.google.com";
String jwksUri = "https://www.googleapis.com/oauth2/v3/certs";
// Get the ID of the key used to sign the token.
DecodedJWT unverifiedJwt = JWT.decode(token);
String keyId = unverifiedJwt.getKeyId();
// Get the public key from Google.
JwkProvider googleCerts = new UrlJwkProvider(new URL(jwksUri), null, null);
PublicKey publicKey = googleCerts.get(keyId).getPublicKey();
// Verify and decode the token.
Algorithm rsa = Algorithm.RSA256((RSAPublicKey) publicKey, null);
JWTVerifier verifier = JWT.require(rsa)
.withIssuer(issuer)
// Get your apps' client IDs from the API console:
// https://console.developers.google.com/apis/credentials?project=_
.withAudience("123456789-abcedfgh.apps.googleusercontent.com",
"123456789-ijklmnop.apps.googleusercontent.com",
"123456789-qrstuvwx.apps.googleusercontent.com")
.acceptLeeway(Long.MAX_VALUE) // Don't check for expiration.
.build();
jwt = verifier.verify(token);
} catch (JwkException e) {
// Key not found. Return HTTP 400.
} catch (InvalidClaimException e) {
} catch (JWTDecodeException exception) {
// Malformed token. Return HTTP 400.
} catch (MalformedURLException e) {
// Invalid JWKS URI.
}
return jwt;
}
Python
import json
import jwt # pip install pyjwt
import requests # pip install requests
def validate_security_token(token, client_ids):
# Get Google's RISC configuration.
risc_config_uri = 'https://accounts.google.com/.well-known/risc-configuration'
risc_config = requests.get(risc_config_uri).json()
# Get the public key used to sign the token.
google_certs = requests.get(risc_config['jwks_uri']).json()
jwt_header = jwt.get_unverified_header(token)
key_id = jwt_header['kid']
public_key = None
for key in google_certs['keys']:
if key['kid'] == key_id:
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(key))
if not public_key:
raise Exception('Public key certificate not found.')
# In this situation, return HTTP 400
# Decode the token, validating its signature, audience, and issuer.
try:
token_data = jwt.decode(token, public_key, algorithms='RS256',
options={'verify_exp': False},
audience=client_ids, issuer=risc_config['issuer'])
except:
raise
# Validation failed. Return HTTP 400.
return token_data
# Get your apps' client IDs from the API console:
# https://console.developers.google.com/apis/credentials?project=_
client_ids = ['123456789-abcedfgh.apps.googleusercontent.com',
'123456789-ijklmnop.apps.googleusercontent.com',
'123456789-qrstuvwx.apps.googleusercontent.com']
token_data = validate_security_token(token, client_ids)
如果權杖有效且已成功解碼,則傳回 HTTP 狀態 202。接著,處理權杖指定的安全性事件。
2. 處理安全性事件
解碼之後,安全性事件權杖如以下範例所示:
{
"iss": "https://accounts.google.com/",
"aud": "123456789-abcedfgh.apps.googleusercontent.com",
"iat": 1508184845,
"jti": "756E69717565206964656E746966696572",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/account-disabled": {
"subject": {
"subject_type": "iss-sub",
"iss": "https://accounts.google.com/",
"sub": "7375626A656374"
},
"reason": "hijacking"
}
}
}
iss
和 aud
憑證表示權杖核發單位 (Google) 和權杖的接收者 (您的服務)。您在上一個步驟中驗證了這些版權聲明。
jti
憑證是識別單一安全性事件的字串,且專屬於串流。您可以使用這個 ID 來追蹤您收到的安全性事件。
events
宣告包含權杖代表的安全性事件相關資訊。此要求是從事件類型 ID 對應至 subject
憑證附加資訊,用於指出這個事件的使用者,以及可能發生的事件相關詳細資料。
subject
憑證附加資訊是含有特定使用者的專屬 Google 帳戶 ID (sub
)。這個 Google 帳戶 ID 與新登入 Google 帳戶 (JavaScript、HTML) 程式庫、舊版 Google 登入程式庫或 OpenID Connect 所核發的 JWT ID 權杖中包含的 ID (sub
) 相同。憑證的 subject_type
為 id_token_claims
時,也可能包含 email
欄位,包含使用者的電子郵件地址。
使用 events
要求中的資訊,針對指定使用者帳戶針對事件類型採取適當行動。
OAuth 權杖 ID
針對個別權杖的 OAuth 事件,權杖主體 ID 類型包含下列欄位:
token_type
:僅支援refresh_token
。token_identifier_alg
:可能的值如下表所示。token
:請參閱下表。
token_identifier_alg | 符記 |
---|---|
prefix |
權杖的前 16 個字元。 |
hash_base64_sha512_sha512 |
權杖的雙重雜湊,使用 SHA-512。 |
如果整合這些事件,建議您根據這些可能的值為權杖建立索引,以便在收到事件時快速比對結果。
支援的事件類型
跨帳戶防護支援下列類型的安全性事件:
事件類型 | 屬性 | 回應方式 |
---|---|---|
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked |
必要:結束目前開啟的工作階段,重新保護使用者帳戶。 | |
https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked |
必要:如果權杖用於 Google 登入,請終止目前開啟的工作階段。此外,您可以建議使用者設定替代登入方式。 建議項目:如果權杖用於存取其他 Google API,請刪除使用者儲存的任何 OAuth 權杖。 |
|
https://schemas.openid.net/secevent/oauth/event-type/token-revoked |
如要瞭解權杖 ID,請參閱 OAuth 權杖 ID 一節 |
必要:如果儲存對應的更新權杖,請刪除權杖,並在下次需要存取權杖時要求使用者重新同意。 |
https://schemas.openid.net/secevent/risc/event-type/account-disabled |
reason=hijacking 、reason=bulk-account |
必要:如果帳戶遭到停用的原因為 建議事項:如果帳戶遭到停用的原因為 建議做法:如未提供原因,請停用使用者的 Google 登入功能,並使用與使用者 Google 帳戶相關聯的電子郵件地址 (通常不需要 Gmail 帳戶) 停用帳戶救援功能。為使用者提供備用登入方式。 |
https://schemas.openid.net/secevent/risc/event-type/account-enabled |
建議做法:為使用者重新啟用 Google 登入功能,並使用使用者的 Google 帳戶電子郵件地址重新啟用帳戶救援功能。 | |
https://schemas.openid.net/secevent/risc/event-type/account-purged |
建議做法:刪除使用者帳戶,或提供其他登入方式。 | |
https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required |
建議:留意服務中的可疑活動,並採取適當行動。 | |
https://schemas.openid.net/secevent/risc/event-type/verification |
狀態=state | 建議項目:記錄已收到測試權杖。 |
重複和錯過的活動
跨帳戶保護措施會嘗試重新提交認為尚未提交的事件。因此,您有時可能會多次收到相同的事件。如果這樣做可能會重複執行動作,讓使用者感到不便,請考慮使用 jti
憑證 (活動的專屬 ID) 來簡化事件。我們提供 Google Cloud Dataflow 等外部工具,可能有助於執行去識別化資料集。
請注意,事件傳送會受限制次數限制,因此如果接收器長時間處於停機狀態,您可能會永久遺失部分事件。
註冊接收器
如要開始接收安全性事件,請使用 RISC API 註冊接收器端點。向 RISC API 發出的呼叫必須附帶授權權杖。
您只會收到應用程式使用者的安全事件,因此您必須在 GCP 專案中設定 OAuth 同意畫面,做為以下步驟。
1. 產生授權權杖
如要產生 RISC API 的授權權杖,請建立含有下列憑證的 JWT:
{ "iss": SERVICE_ACCOUNT_EMAIL, "sub": SERVICE_ACCOUNT_EMAIL, "aud": "https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService", "iat": CURRENT_TIME, "exp": CURRENT_TIME + 3600 }
使用服務帳戶的私密金鑰簽署 JWT,您可以在建立服務帳戶金鑰時下載的 JSON 檔案中找到該金鑰。
例如:
Java
使用 java-jwt 和 Google 的驗證程式庫:
public static String makeBearerToken() {
String token = null;
try {
// Get signing key and client email address.
FileInputStream is = new FileInputStream("your-service-account-credentials.json");
ServiceAccountCredentials credentials =
(ServiceAccountCredentials) GoogleCredentials.fromStream(is);
PrivateKey privateKey = credentials.getPrivateKey();
String keyId = credentials.getPrivateKeyId();
String clientEmail = credentials.getClientEmail();
// Token must expire in exactly one hour.
Date issuedAt = new Date();
Date expiresAt = new Date(issuedAt.getTime() + 3600000);
// Create signed token.
Algorithm rsaKey = Algorithm.RSA256(null, (RSAPrivateKey) privateKey);
token = JWT.create()
.withIssuer(clientEmail)
.withSubject(clientEmail)
.withAudience("https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService")
.withIssuedAt(issuedAt)
.withExpiresAt(expiresAt)
.withKeyId(keyId)
.sign(rsaKey);
} catch (ClassCastException e) {
// Credentials file doesn't contain a service account key.
} catch (IOException e) {
// Credentials file couldn't be loaded.
}
return token;
}
Python
import json
import time
import jwt # pip install pyjwt
def make_bearer_token(credentials_file):
with open(credentials_file) as service_json:
service_account = json.load(service_json)
issuer = service_account['client_email']
subject = service_account['client_email']
private_key_id = service_account['private_key_id']
private_key = service_account['private_key']
issued_at = int(time.time())
expires_at = issued_at + 3600
payload = {'iss': issuer,
'sub': subject,
'aud': 'https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService',
'iat': issued_at,
'exp': expires_at}
encoded = jwt.encode(payload, private_key, algorithm='RS256',
headers={'kid': private_key_id})
return encoded
auth_token = make_bearer_token('your-service-account-credentials.json')
這個授權權杖可用於進行 RISC API 呼叫一小時。權杖到期後,請產生新的權杖,以便繼續呼叫 RISC API 呼叫。
2. 呼叫 RISC 串流設定 API
取得授權權杖後,即可使用 RISC API 設定專案的安全性事件串流,包括註冊接收器端點。
如要這麼做,請向 https://risc.googleapis.com/v1beta/stream:update
提出 HTTPS POST 要求,並指定接收端端點和安全性事件類型:
POST /v1beta/stream:update HTTP/1.1 Host: risc.googleapis.com Authorization: Bearer AUTH_TOKEN { "delivery": { "delivery_method": "https://schemas.openid.net/secevent/risc/delivery-method/push", "url": RECEIVER_ENDPOINT }, "events_requested": [ SECURITY_EVENT_TYPES ] }
例如:
Java
public static void configureEventStream(final String receiverEndpoint,
final List<String> eventsRequested,
String authToken) throws IOException {
ObjectMapper jsonMapper = new ObjectMapper();
String streamConfig = jsonMapper.writeValueAsString(new Object() {
public Object delivery = new Object() {
public String delivery_method =
"https://schemas.openid.net/secevent/risc/delivery-method/push";
public String url = receiverEndpoint;
};
public List<String> events_requested = eventsRequested;
});
HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:update");
updateRequest.addHeader("Content-Type", "application/json");
updateRequest.addHeader("Authorization", "Bearer " + authToken);
updateRequest.setEntity(new StringEntity(streamConfig));
HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
StatusLine responseStatus = updateResponse.getStatusLine();
int statusCode = responseStatus.getStatusCode();
HttpEntity entity = updateResponse.getEntity();
// Now handle response
}
// ...
configureEventStream(
"https://your-service.example.com/security-event-receiver",
Arrays.asList(
"https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required",
"https://schemas.openid.net/secevent/risc/event-type/account-disabled"),
authToken);
Python
import requests
def configure_event_stream(auth_token, receiver_endpoint, events_requested):
stream_update_endpoint = 'https://risc.googleapis.com/v1beta/stream:update'
headers = {'Authorization': 'Bearer {}'.format(auth_token)}
stream_cfg = {'delivery': {'delivery_method': 'https://schemas.openid.net/secevent/risc/delivery-method/push',
'url': receiver_endpoint},
'events_requested': events_requested}
response = requests.post(stream_update_endpoint, json=stream_cfg, headers=headers)
response.raise_for_status() # Raise exception for unsuccessful requests
configure_event_stream(auth_token, 'https://your-service.example.com/security-event-receiver',
['https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required',
'https://schemas.openid.net/secevent/risc/event-type/account-disabled'])
如果要求傳回 HTTP 200,表示事件串流已成功設定,且接收器端點應開始收到安全性事件權杖。下一節將說明如何測試串流設定和端點,以確認一切運作正常。
取得及更新目前的串流設定
如果您日後想要修改串流設定,只要向 https://risc.googleapis.com/v1beta/stream
發出授權 GET 要求以取得目前的串流設定,修改回應內文,然後將修改後的設定張貼回 https://risc.googleapis.com/v1beta/stream:update
,如上所述。
停止並繼續事件串流
如果您需要停止 Google 的事件串流,請在要求主體中透過 { "status": "disabled" }
向 https://risc.googleapis.com/v1beta/stream/status:update
發出授權 POST 要求。停用串流後,Google 不會將事件傳送至端點,也不會在發生安全性事件時進行緩衝事件。如要重新啟用事件串流,請將 { "status": "enabled" }
張貼至同一個端點。
3. 選用:測試串流設定
您可以透過事件串流傳送驗證權杖,驗證串流設定和接收器端點是否正常運作。這組權杖可包含不重複的字串,您可以使用此字串驗證端點是否已收到憑證。如要使用這個流程,請務必在註冊接收器時訂閱 https://schemas.openid.net/secevent/risc/event-type/verification 事件類型。
如要申請驗證權杖,請向 https://risc.googleapis.com/v1beta/stream:verify
提出授權的 HTTPS POST 要求。在要求內文中,指定一些識別字串:
{ "state": "ANYTHING" }
例如:
Java
public static void testEventStream(final String stateString,
String authToken) throws IOException {
ObjectMapper jsonMapper = new ObjectMapper();
String json = jsonMapper.writeValueAsString(new Object() {
public String state = stateString;
});
HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:verify");
updateRequest.addHeader("Content-Type", "application/json");
updateRequest.addHeader("Authorization", "Bearer " + authToken);
updateRequest.setEntity(new StringEntity(json));
HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
StatusLine responseStatus = updateResponse.getStatusLine();
int statusCode = responseStatus.getStatusCode();
HttpEntity entity = updateResponse.getEntity();
// Now handle response
}
// ...
testEventStream("Test token requested at " + new Date().toString(), authToken);
Python
import requests
import time
def test_event_stream(auth_token, nonce):
stream_verify_endpoint = 'https://risc.googleapis.com/v1beta/stream:verify'
headers = {'Authorization': 'Bearer {}'.format(auth_token)}
state = {'state': nonce}
response = requests.post(stream_verify_endpoint, json=state, headers=headers)
response.raise_for_status() # Raise exception for unsuccessful requests
test_event_stream(auth_token, 'Test token requested at {}'.format(time.ctime()))
如果要求成功,驗證權杖將傳送至您註冊的端點。舉例來說,如果您的端點只要以驗證記錄的方式處理驗證權杖,您可以查看這些記錄來確認已收到權杖。
錯誤代碼參考資料
RISC API 可能會傳回下列錯誤:
錯誤代碼 | 錯誤訊息 | 建議操作 |
---|---|---|
400 | 串流設定必須包含 $fieldname 欄位。 | 傳送至 https://risc.googleapis.com/v1beta/stream:update 端點的要求無效或無法剖析。請在要求中加入 $fieldname。 |
401 | 未經授權。 | 無法提供授權,請務必在要求中附加 授權權杖,且權杖有效且並未過期。 |
403 | 推送端點必須是 HTTPS 網址。 | 您的傳送端點 (也就是您預期將 RISC 事件傳送至的端點) 必須是 HTTPS。我們不會將 RISC 事件傳送至 HTTP 網址。 |
403 | 現有串流設定沒有符合 RISC 規格規格的提交方式。 | 您的 Google Cloud 專案已有 RISC 設定。如果您使用的是 Firebase 並啟用 Google 登入功能,Firebase 就會為您的專案管理 RISC,您將無法建立自訂設定。如果您不是使用 Firebase 專案的 Google 登入功能,請停用此功能,然後在一小時後再次嘗試更新。 |
403 | 找不到專案。 | 確認使用正確的服務帳戶執行正確的專案。您使用的服務帳戶可能與已刪除的專案相關聯。瞭解 如何查看與專案相關聯的所有服務帳戶。 |
403 | 服務帳戶必須具備存取 RISC 設定的權限 | 前往專案的 API Console ,並將「RISC 設定管理員」角色 (roles/riscconfigs.admin ) 指派給呼叫專案的服務帳戶,請按照這些操作說明操作。 |
403 | 串流服務帳戶只能由服務帳戶呼叫。 | 進一步瞭解如何透過服務帳戶呼叫 Google API。 |
403 | 推送端點不屬於任何專案網域。 | 每個專案都有一組授權網域。如果推送端點 (也就是預期將接收 RISC 事件的端點) 並未託管於任何端點,您必須為該端點新增端點的網域。 |
403 | 如要使用這個 API,您的專案必須設定至少一個 OAuth 用戶端。 | 只有在您建構支援 Google 登入的應用程式時,RISC 才能順利運作。 這項連線需要 OAuth 用戶端。如果專案沒有 OAuth 用戶端,可能就不適合使用 RISC。進一步瞭解 Google 的 API 使用 OAuth。 |
403 |
不支援狀態。 狀態無效。 |
目前僅支援串流狀態「enabled 」和「disabled 」。 |
404 |
專案沒有 RISC 設定。 專案目前沒有 RISC 設定,因此無法更新狀態。 |
呼叫 https://risc.googleapis.com/v1beta/stream:update 端點,建立新的串流設定。 |
4XX/5XX | 無法更新狀態。 | 請查看詳細錯誤訊息瞭解詳情。 |
存取權杖範圍
如果您決定使用存取權杖來驗證 RISC API,以下是應用程式必須要求的範圍:
端點 | 範圍 |
---|---|
https://risc.googleapis.com/v1beta/stream/status |
https://www.googleapis.com/auth/risc.status.readonly
或 https://www.googleapis.com/auth/risc.status.readwrite |
https://risc.googleapis.com/v1beta/stream/status:update |
https://www.googleapis.com/auth/risc.status.readwrite |
https://risc.googleapis.com/v1beta/stream |
https://www.googleapis.com/auth/risc.configuration.readonly
或 https://www.googleapis.com/auth/risc.configuration.readwrite
|
https://risc.googleapis.com/v1beta/stream:update |
https://www.googleapis.com/auth/risc.configuration.readwrite |
https://risc.googleapis.com/v1beta/stream:verify |
https://www.googleapis.com/auth/risc.verify |
需要協助嗎?
首先,請參閱我們的錯誤代碼參考資料一節。如果您仍有問題,請前往 Stack Overflow 張貼問題,並加上 #SecEvents 標記。