Protect user accounts with Cross-Account Protection

If your app lets users sign in to their accounts using Google, you can improve
the security of these shared users' accounts by listening and responding to the
security event notifications provided by the Cross-Account Protection service.

These notifications alert you of major changes to the Google Accounts of your
users, which can often also have security implications for their accounts with
your app. For instance, if a user's Google Account were hijacked, it could
potentially lead to compromise of the user's account with your app through email
account recovery or the use of single sign-on.

To help you mitigate the risk potential of such events, Google sends your
service objects called security event tokens. These tokens expose very little
information—just the type of security event and when it occurred, and the
identifier of the affected user—but you can use them to take
appropriate action in response. For example, if a user's Google Account were
compromised, you could temporarily disable Google Sign-in for that user and
prevent account recovery emails from being sent to the user's Gmail address.

Cross-Account Protection is based on the
RISC standard, developed at the OpenID
Foundation.

Important: This data is provided under the Google APIs Terms of
Service and the additional RISC Terms of Service ("RISC
Terms"). These signals may only be used for security, anti-fraud, and session
management purposes. Please review and comply with the RISC Terms; failure to do
so may result in project suspension or account suspension.

Overview

To use Cross-Account Protection with your app or service, you must complete the
following tasks:

Set up your project in the API Console.

Create an event receiver endpoint, to which Google will send security event
tokens. This endpoint is responsible for validating the tokens it receives
and then responding to security events in whatever way you choose.

Prerequisite

You only receive security event tokens for Google users who have granted your
service permission to access their profile information or email addresses. You
get this permission by requesting the profile or email scopes. The
Google Sign-in SDKs request these scopes by default, but
if you don't use the default settings, or if you access Google's OpenID
Connect endpoint directly, ensure you are
requesting at least one of these scopes.

Set up a project in the API Console

Before you can start receiving security event tokens, you must create a service
account and enable the RISC API in your API Console project. You must
use the same API Console project you use to access Google services,
such as Google Sign-in, in your app.

Choose the JSON key type and then click Create. When the key is created,
you will download a JSON file that contains your service account
credentials. Keep this file somewhere safe, but also accessible to your
event receiver endpoint.

While you're on your project's Credentials page, also take note of the client
IDs you use for Google Sign-in. Typically, you have a client ID for each
platform you support. You will need these client IDs to validate security event
tokens, as described in the next section.

To enable the RISC API:

Open the RISC API page in the API Console. Make sure
the project you use to access Google services is still selected.

If you are enabling the API for a project owned by an organization, ensure
you are authorized to bind your organization to the RISC Terms.

Click Enable only if you consent to the RISC Terms.

Create an event receiver endpoint

To receive security event notifications from Google, you create an HTTPS endpoint
that handles HTTPS POST requests. After you register this endpoint (see below),
Google will begin posting cryptographically signed strings called security event
tokens to the endpoint. Security event tokens are signed JWTs that contain
information about a single security-related event.

Important: Ensure that your endpoint, even during testing, stores the received
information in a way that abides by the RISC Terms of Service
and deletes them in a reasonable timeframe.

For each security event token you receive at your endpoint, first validate and
decode the token, then handle the security event as appropriate for your
service. The following sections describe these tasks:

1. Decode and validate the security event token

Because security event tokens are a specific kind of JWT, you can use any
JWT library, such as one listed on jwt.io, to decode and
validate them. Whichever library you use, your token validation code must do the
following:

Get the Cross-Account Protection issuer identifier (issuer) and signing key
certificate URI (jwks_uri) from Google's RISC configuration document,
which you can find at
https://accounts.google.com/.well-known/risc-configuration.

Using the JWT library of your choice, get the signing key ID from the header
of the security event token.

From Google's signing key certificate document, get the public key with the
key ID you got in the previous step. If the document doesn't contain a key
with the ID you're looking for, it is likely the security event token is
invalid, and your endpoint should return HTTP error 400.

Using the JWT library of your choice, verify the following:

The security event token is signed using the public key you got in the
previous step.

The aud claim of the token is one of your apps' client IDs.

The iss claim of the token matches the issuer identifier you got from
the RISC discovery document.
Note that you don't need to verify the token's expiration (exp) because
security event tokens represent historical events and as such, don't expire.

The iss and aud claims indicate the issuer of the token (Google) and the
token's intended recipient (your service). You verified these claims in the
previous step.

The jti claim is a string that identifies a single security event, and is
unique to the stream. You can use this identifier to track which security events
you have received.

The events claim contains information about the security event the token
represents. This claim is a mapping from an event type identifier to a subject
claim, which specifies the user this event concerns, and to any additional
details about the event that might be available.

The subject claim identifies a particular user with the user's unique Google
Account ID (sub). This ID is the same as the identifier contained in the ID
tokens produced by Google Sign-in. When the subject_type of the
claim is id_token_claims, it might also include an email field with the
user's email address.

Use the information in the events claim to take appropriate action for the
event type on the specified user's account.

Supported event types

Cross-Account Protection supports the following types of security events:

Event Type

Attributes

How to Respond

https://schemas.openid.net/secevent/risc/event-type/sessions-revoked

Required: Re-secure the user's account by ending their currently
open sessions.

https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked

Required: If the token is for Google Sign-in, terminate their
currently open sessions. Additionally, you may want to suggest to the user to
set up an alternate sign-in method.

Suggested: If the token is for access to other Google APIs, delete
any of the user's OAuth tokens you have stored.

https://schemas.openid.net/secevent/risc/event-type/account-disabled

reason=hijacking,reason=bulk-account

Required: If the reason the account was disabled was
hijacking, re-secure the user's account by ending their
currently open sessions.

Suggested: If the reason the account was disabled was
bulk-account, analyze the user's activity on your service and
determine appropriate follow-up actions.

Suggested: If no reason was provided, disable Google Sign-in for the
user and disable account recovery using the email address associated with
the user's Google Account (usually, but not necessarily, a Gmail account).
Offer the user an alternate sign-in method.

Suggested: Look out for suspicious activity on your service and take
appropriate action.

https://schemas.openid.net/secevent/risc/event-type/verification

state=state

Suggested: Log that a test token was received.

Duplicated and missed events

Cross-Account Protection will attempt to redeliver events that it believes have
not been delivered. Therefore, you may sometimes receive the same event
multiple times. If this could cause repeated actions that inconvenience your
users, consider using the jti claim (which is a unique identifier for an
event) to de-dup the events. There are external tools like Google Cloud
Dataflow that may help you to execute
the de-dup dataflow.

Note that events are delivered with limited retries so if your receiver is down
for an extended period of time you may permanently miss some events.

Register your receiver

To begin receiving security events, register your receiver endpoint using the
RISC API. Calls to the RISC API must be accompanied by an authorization token.

1. Generate an authorization token

To generate an authorization token for the RISC API, create a JWT with the
following claims:

If the request returns HTTP 200, the event stream was successfully configured
and your receiver endpoint should start receiving security event tokens. The
next section describes how you can test your stream configuration and endpoint
to verify everything is working correctly together.

Get and update your current stream configuration

If, in the future, you ever want to modify your stream configuration, you can do
so by making an authorized GET request to https://risc.googleapis.com/v1beta/stream to get the
current stream configuration, modifying the response body, and then POSTing the
modified configuration back to https://risc.googleapis.com/v1beta/stream:update as described above.

Stop and resume the event stream

If you ever need to stop the event stream from Google, make an authorized POST
request to https://risc.googleapis.com/v1beta/stream/status:update with { "status": "disabled" }
in the request body. While the stream is deactivated, Google doesn't send events
to your endpoint and doesn't buffer security events when they occur. To
reenable the event stream, POST { "status": "enabled" } to the same endpoint.

3. Optional: Test your stream configuration

You can verify that your stream configuration and receiver endpoint are working
together correctly by sending a verification token through your event stream.
This token can contain a unique string that you can use use to verify that the
token was received at your endpoint.

To request a verification token, make an authorized HTTPS POST request to
https://risc.googleapis.com/v1beta/stream:verify. In the body of the request, specify some
identifying string:

If the request succeeds, the verification token will be sent to the endpoint you
registered. Then, for example, if your endpoint handles verification tokens by
simply logging them, you can examine your logs to confirm the token was
received.

Error code reference

The following errors can be returned by the RISC API:

Error Code

Error Message

Suggested Actions

400

Stream configuration must contain $fieldname field.

Your request to the https://risc.googleapis.com/v1beta/stream:update endpoint is invalid or cannot be
parsed. Please include $fieldname in your request.

401

Unauthorized.

Authorization failed. Be sure you attached an
authorization token with the request and that the token is valid
and hasn't expired.

403

The delivery endpoint must be an HTTPS URL.

Your delivery endpoint (i.e. the endpoint you expect RISC events to be
delivered to) must be HTTPS. We do not send RISC events to HTTP URLs.

403

Existing stream configuration does not have spec-compliant delivery
method for RISC.

Your Google Cloud project must already have a RISC configuration. If
you are using Firebase and have Google Sign-In enabled, then Firebase will be
managing RISC for your project; you will not be able to create a custom
configuration. If you are not using Google Sign-In for your Firebase project,
please disable it, and then try to update again after an hour.

The delivery endpoint does not belong to any of your project's domains.

Every project has a set of
authorized domains.
If your delivery endpoint (i.e. the endpoint you expect RISC events to
be delivered to) is not hosted on one of them, we require that you add
the endpoint's domain to that set.

403

To use this API your project must have at least one OAuth client configured.

RISC only works if you build an app that supports
Google Sign In.
This connection requires an OAuth client. If your project has no OAuth
clients, it's likely that RISC will not be useful for you. Learn more
about Google's use of OAuth for our APIs.

403

Unsupported status.

Invalid status.

We only support the stream statuses “enabled” and
“disabled” at this time.

404

Project has no RISC configuration.

Project has no existing RISC configuration, cannot update status.

Call the https://risc.googleapis.com/v1beta/stream:update endpoint to create a new stream configuration.

4XX/5XX

Unable to update status.

Check the detailed error message for more information.

Access token scopes

Should you decide to use access tokens for authenticating to the RISC API, these
are the scopes your application must request:

Endpoint

Scope

https://risc.googleapis.com/v1beta/stream/status

https://www.googleapis.com/auth/risc.status.readonly
OR 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
OR https://www.googleapis.com/auth/risc.configuration.readwrite