クロスアカウント保護機能でユーザー アカウントを保護する

アプリでユーザーが Google を使用してアカウントにログインできるようにしている場合は、クロスアカウント保護サービスから提供されるセキュリティ イベント通知をリッスンして応答することで、共有ユーザーのアカウントのセキュリティを強化できます。

これらの通知は、ユーザーの Google アカウントに大きな変更があったことを通知するもので、多くの場合、アプリのアカウントのセキュリティにも影響する可能性があります。たとえば、ユーザーの Google アカウントが不正使用された場合、メール アカウントの復元やシングル サインオンの使用によって、アプリのユーザー アカウントが不正使用される可能性があります。

このようなイベントの潜在的なリスクを軽減するために、Google はセキュリティ イベント トークンと呼ばれるサービス オブジェクトを送信します。これらのトークンは、セキュリティ イベントのタイプ、発生日時、影響を受けるユーザーの ID のみを公開しますが、それらを使用して適切な対応を行うことができます。たとえば、ユーザーの Google アカウントが不正使用された場合は、そのユーザーの [Google でログイン] を一時的に無効にして、アカウント復元メールがユーザーの Gmail アドレスに送信されないようにできます。

クロスアカウント保護は、OpenID Foundation で開発された RISC 標準に基づいています。

概要

アプリまたはサービスでクロスアカウント保護を使用するには、次のタスクを完了する必要があります。

  1. API Consoleでプロジェクトを設定します。

  2. Google がセキュリティ イベント トークンを送信するイベント受信エンドポイントを作成します。このエンドポイントは、受信したトークンを検証し、選択した方法でセキュリティ イベントに応答します。

  3. エンドポイントを Google に登録して、セキュリティ イベント トークンの受信を開始します。

前提条件

セキュリティ イベント トークンは、プロフィール情報またはメールアドレスへのアクセスをサービスに許可した Google ユーザーに対してのみ受け取ります。この権限を取得するには、profile スコープまたは email スコープをリクエストします。新しい Sign In with Google SDK または以前の Google Sign-in SDK では、これらのスコープがデフォルトでリクエストされますが、デフォルト設定を使用しない場合や、Google の OpenID Connect エンドポイントに直接アクセスする場合は、これらのスコープの少なくとも 1 つをリクエストするようにしてください。

API Consoleでプロジェクトを設定する

セキュリティ イベント トークンの受信を開始するには、サービス アカウントを作成し、API Console プロジェクトで RISC API を有効にする必要があります。アプリで Google サービス(Google ログインなど)にアクセスする場合と同じAPI Console プロジェクトを使用する必要があります。

サービス アカウントを作成するには:

  1. API Console Credentials page を開きます。プロンプトが表示されたら、アプリで Google サービスにアクセスするために使用するAPI Consoleプロジェクトを選択します。

  2. [認証情報を作成] > [サービス アカウント] をクリックします。

  3. こちらの手順に沿って、RISC 構成管理者ロール(roles/riscconfigs.admin)を持つ新しいサービス アカウントを作成します。

  4. 新しく作成したサービス アカウントのキーを作成します。JSON キータイプを選択して [作成] をクリックします。鍵が作成されると、サービス アカウントの認証情報を含む JSON ファイルがダウンロードされます。このファイルは、イベント受信エンドポイントがアクセスできる安全な場所に保管してください。

プロジェクトの認証情報ページで、Google でログインまたは Google ログイン(従来版)に使用するクライアント ID もメモしておいてください。通常、サポートするプラットフォームごとにクライアント ID があります。これらのクライアント ID は、次のセクションで説明するように、セキュリティ イベント トークンを検証するために必要になります。

RISC API を有効にするには:

  1. API Consoleで RISC API ページを開きます。Google サービスへのアクセスに使用するプロジェクトが選択されていることを確認します。

  2. RISC の利用規約を読み、要件を理解します。

    組織が所有するプロジェクトで API を有効にする場合は、組織を RISC 利用規約に拘束する権限があることを確認してください。

  3. RISC 利用規約に同意する場合のみ、[有効にする] をクリックします。

イベント レシーバー エンドポイントを作成する

Google からセキュリティ イベント通知を受け取るには、HTTPS POST リクエストを処理する HTTPS エンドポイントを作成します。このエンドポイントを登録すると(後述)、Google はセキュリティ イベント トークンと呼ばれる暗号署名付き文字列をエンドポイントに投稿します。セキュリティ イベント トークンは、単一のセキュリティ関連イベントに関する情報が含まれる署名付き JWT です。

エンドポイントで受信したセキュリティ イベント トークンごとに、まずトークンを検証してデコードし、サービスに応じてセキュリティ イベントを処理します。不正な攻撃を防ぐため、デコードする前にイベント トークンを検証することが不可欠です。以降のセクションでは、これらのタスクについて説明します。

1. セキュリティ イベント トークンをデコードして検証する

セキュリティ イベント トークンは特定の種類の JWT であるため、jwt.io に記載されているものなど、任意の JWT ライブラリを使用してデコードと検証を行うことができます。どのライブラリを使用する場合でも、トークン検証コードは次の処理を行う必要があります。

  1. Google の RISC 構成ドキュメント(https://accounts.google.com/.well-known/risc-configuration)から、クロスアカウント保護の発行元 ID(issuer)と署名鍵証明書 URI(jwks_uri)を取得します。
  2. 任意の JWT ライブラリを使用して、セキュリティ イベント トークンのヘッダーから署名鍵 ID を取得します。
  3. Google の署名鍵証明書ドキュメントから、前の手順で取得した鍵 ID を使用して公開鍵を取得します。ドキュメントに目的の ID を含むキーが含まれていない場合、セキュリティ イベント トークンが無効である可能性があり、エンドポイントから HTTP エラー 400 が返されます。
  4. 任意の JWT ライブラリを使用して、次のことを確認します。
    • セキュリティ イベント トークンは、前の手順で取得した公開鍵を使用して署名されます。
    • トークンの aud クレームは、アプリのクライアント ID のいずれかです。
    • トークンの iss クレームが、RISC ディスカバリ ドキュメントから取得した発行元 ID と一致している。セキュリティ イベント トークンは過去のイベントを表すため、期限切れにならないため、トークンの有効期限(exp)を確認する必要はありません。

次に例を示します。

Java

java-jwtjwks-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"
    }
  }
}

issaud のクレームは、トークンの発行元(Google)とトークンの対象受信者(お客様のサービス)を示します。これらの申し立ては、前のステップで確認しました。

jti クレームは、単一のセキュリティ イベントを識別する文字列で、ストリームに固有です。この識別子を使用して、受信したセキュリティ イベントを追跡できます。

events クレームには、トークンが表すセキュリティ イベントに関する情報が含まれます。このクレームは、イベントタイプ ID から subject クレームへのマッピングです。このクレームには、このイベントに関連するユーザーと、利用可能なイベントの詳細が指定されます。

subject クレームは、ユーザーの一意の Google アカウント ID(sub)を使用して特定のユーザーを識別します。この Google アカウント ID は、新しい「Google でログイン」(JavascriptHTML)ライブラリ、以前の Google ログイン ライブラリ、OpenID Connect によって発行された JWT ID トークンに含まれる ID(sub)と同じです。申し立ての subject_typeid_token_claims の場合、ユーザーのメールアドレスを含む email フィールドも含まれる場合があります。

events クレームの情報を使用して、指定されたユーザーのアカウントのイベントタイプに対して適切な措置を講じます。

OAuth トークン ID

個々のトークンに関する OAuth イベントの場合、トークンのサブジェクト ID タイプには次のフィールドが含まれます。

  • token_type: refresh_token のみがサポートされています。

  • token_identifier_alg: 使用できる値については、下記の表をご覧ください。

  • token: 下記の表を参照してください。

token_identifier_alg token
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 トークン識別子については、OAuth トークン識別子のセクションをご覧ください。

必須: 対応する更新トークンを保存している場合は、そのトークンを削除し、次回アクセス トークンが必要なときにユーザーに再度同意を求めます。

https://schemas.openid.net/secevent/risc/event-type/account-disabled reason=hijacking
reason=bulk-account

必須: アカウントが無効になった理由が hijacking の場合は、現在開いているセッションを終了して、ユーザーのアカウントを再保護します。

推奨: アカウントが無効になった理由が 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-credential-change-required 推奨: サービスで不審なアクティビティがないかを確認し、適切な対応を講じます。
https://schemas.openid.net/secevent/risc/event-type/verification state=state 推奨: テストトークンが受信されたことをログに記録します。

重複するイベントと期限切れの予定

クロスアカウント保護は、配信されていないと判断されたイベントの再配信を試みます。そのため、同じイベントが複数回受信されることがあります。これがユーザーに不便な繰り返しのアクションを引き起こす可能性がある場合は、jti クレーム(イベントの一意の識別子)を使用してイベントの重複を排除することを検討してください。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-jwtGoogle の認証ライブラリを使用する場合:

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')

この認可トークンを使用して、1 時間 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 に POST します。

イベント ストリームを停止して再開する

Google からのイベント ストリームを停止する必要がある場合は、リクエスト本文に { "status": "disabled" } を指定して、https://risc.googleapis.com/v1beta/stream/status:update に承認済みの POST リクエストを送信します。ストリームが無効になっている間、Google はエンドポイントにイベントを送信せず、セキュリティ イベントが発生したときにバッファリングしません。イベント ストリームを再度有効にするには、同じエンドポイントに { "status": "enabled" } を POST します。

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 URL である必要があります。 配信エンドポイント(RISC イベントが配信されるエンドポイント)は HTTPS である必要があります。RISC イベントは HTTP URL に送信されません。
403 既存のストリーミング構成に RISC の仕様に準拠した配信方法がない。 Google Cloud プロジェクトに RISC 構成がすでに存在している必要があります。Firebase を使用していて、Google ログインを有効にしている場合、Firebase がプロジェクトの RISC を管理するため、カスタム構成を作成することはできません。Firebase プロジェクトで Google ログインを使用していない場合は、無効にしてから 1 時間後にもう一度更新を試してください。
403 プロジェクトが見つかりませんでした。 正しいプロジェクトに正しいサービス アカウントを使用していることを確認します。削除されたプロジェクトに関連付けられているサービス アカウントを使用している可能性があります。 プロジェクトに関連付けられているすべてのサービス アカウントを確認する方法をご覧ください。
403 サービス アカウントに RISC 構成にアクセスするための権限が必要 プロジェクトの API Console に移動し、こちらの手順に沿って、プロジェクトを呼び出すサービス アカウントに「RISC 構成管理者」ロール(roles/riscconfigs.admin)を割り当てます。
403 ストリーム管理 API は、サービス アカウントによってのみ呼び出す必要があります。 サービス アカウントを使用して Google API を呼び出す方法の詳細については、こちらをご覧ください。
403 配信エンドポイントがプロジェクトのドメインに属していません。 すべてのプロジェクトには、一連の承認済みドメインがあります。配信エンドポイント(RISC イベントが配信されるエンドポイント)がこれらのいずれにもホストされていない場合は、エンドポイントのドメインをそのセットに追加する必要があります。
403 この API を使用するには、プロジェクトに少なくとも 1 つの OAuth クライアントを構成する必要があります。 RISC は、Google ログインをサポートするアプリをビルドする場合にのみ機能します。この接続には 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

お困りの場合

まず、エラーコードの参照セクションをご覧ください。それでも不明な点がある場合は、#SecEvents タグを付けて Stack Overflow に投稿してください。