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

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

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

このようなイベントのリスクを軽減するため、Google はセキュリティ イベント トークンと呼ばれるサービス オブジェクトを送信します。これらのトークンが公開する情報はごくわずかです。セキュリティ イベントの種類、発生日時、影響を受けるユーザーの識別子のみです。ただし、これらのトークンを使用して、適切な対応を取ることができます。たとえば、ユーザーの Google アカウントが不正使用された場合、そのユーザーの「Google でログイン」を一時的に無効にして、アカウント復元メールがユーザーの Gmail アドレスに送信されないようにすることができます。

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

概要

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

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

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

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

前提条件

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

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

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

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

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

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

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

  4. (省略可)Google Cloud 組織でサービス アカウント キーの作成が許可されていて、JWT にローカルで署名する場合は、新しく作成したサービス アカウントのキーを作成します。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-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 クレームは、単一のセキュリティ イベントを識別する文字列であり、ストリームに固有です。この識別子を使用して、受信したセキュリティ イベントを追跡できます。

events クレームには、トークンが表すセキュリティ イベントに関する情報が含まれています。このクレームは、イベントタイプ識別子から 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 トークン識別子

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

  • 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 トークン ID については、OAuth トークン ID セクションをご覧ください。

必須: 対応する更新トークンを保存している場合は、それを削除し、アクセス トークンが必要になったときにユーザーに再同意をリクエストします。

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 の認証トークンを生成するには、サービス アカウントの権限借用で Google Cloud CLI(gcloud)を使用するか(iam.disableServiceAccountKeyCreation が適用されている場合や、1 回限りの CLI 設定の場合に推奨)、サービス アカウントの秘密鍵を使用して JWT にローカルで署名します。

オプション A: gcloud を使用して有効期間の短いアクセス トークンを生成する(JSON キーは不要)

ユーザー アカウントにサービス アカウントのサービス アカウント トークン作成者ロール(roles/iam.serviceAccountTokenCreator)がある場合は、必要な RISC 構成スコープを持つ有効期間の短い OAuth 2.0 アクセス トークンをターミナルから直接作成できます。

AUTH_TOKEN=$(gcloud auth print-access-token \
  --impersonate-service-account=SERVICE_ACCOUNT_EMAIL \
  --scopes=https://www.googleapis.com/auth/risc.configuration.readwrite,https://www.googleapis.com/auth/risc.verify,https://www.googleapis.com/auth/risc.status.readwrite)

RISC API で使用可能な OAuth 2.0 スコープの詳細については、アクセス トークンのスコープをご覧ください。

オプション B: サービス アカウント キーを使用して自己署名 JWT を作成する

また、ネットワーク往復なしでローカルで認証トークンを生成するには、次のクレームを含む 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')

この認証トークンは、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 ログインを使用していない場合は、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 に投稿してください。