
Google Cross-Account Protection (RISC): The Receiver Endpoint Rules Behind token-revoked
If users sign in to your product with Google, Google will tell you when one of those Google Accounts is hijacked, disabled, or has a token revoked. The signal is free. Actually receiving it is a gated, cryptographically strict integration with a service account role, an authorized-domain requirement, and a token-indexing decision you cannot retrofit cheaply.
Google Cross-Account Protection RISC: what it sends you
Cross-Account Protection is Google’s implementation of the RISC standard from the OpenID Foundation. When something security-relevant happens to a Google Account that is linked to your service, Google pushes a security event token to an HTTPS endpoint you registered — a signed JWT describing one event.
The design is deliberately minimal. A security event token exposes the event type, when it occurred, and an identifier for the affected user. It is not a data feed and it is not an audit log. Google is explicit that these signals may only be used for security, anti-fraud, and session-management purposes, under a separate set of RISC Terms of Service that sit on top of the standard Google APIs Terms — and that failure to comply may result in project or account suspension.
What you get
A signed JWT per event, containing the event type, a jti event identifier, and a subject identifying the user by their Google Account sub — the same sub your ID tokens already carry.
What you do not get
No profile data, no reason narrative beyond a small fixed set of values, no events for Google Workspace users, and no delivery promise if your receiver is down for an extended period. Retries are limited.
Google Cross-Account Protection RISC lets a service receive security event tokens when account access changes. The receiver must validate the event, map it to a user, and process it safely.
For Google Cross-Account Protection RISC, design the receiver around token-revoked events, duplicate delivery, replay protection, and clear response codes.
The prerequisite that disqualifies projects before they start
You only receive security event tokens for Google users who granted your service permission to access their profile information or email address — meaning your app must be requesting the profile or email scope. Sign In With Google requests these by default, but an integration that hits Google’s OpenID Connect endpoint directly with a custom scope list may not, and in that case the stream is silently empty rather than broken.
The second prerequisite is organisational rather than technical. Registering a receiver requires a service account holding the roles/riscconfigs.admin role in the same API Console project you already use for Google Sign-In, with the RISC API enabled and the RISC Terms accepted. If the project belongs to an organisation, someone with authority to bind that organisation to those terms has to click Enable. That is a legal sign-off, not a developer task, and it is where a surprising number of these builds sit for weeks.
The seven event types, and which responses Google calls mandatory
Google distinguishes between responses that are Required and responses that are Suggested. Subscribing to an event and then ignoring the required response is a policy problem, not just an engineering shortcut.
| Event type (short name) | Google’s stated response |
|---|---|
sessions-revoked | Required: end the user’s currently open sessions in your app. |
tokens-revoked | Required: if the token was for Google Sign-in, terminate open sessions and consider prompting the user to set up an alternate sign-in method. Suggested: delete any stored OAuth tokens for that user. |
token-revoked | Required: if you store the corresponding refresh token, delete it and force re-consent the next time an access token is needed. |
account-disabled | Required when reason=hijacking: end open sessions. Suggested for reason=bulk-account or no reason: analyse activity, disable Google sign-in and email-based account recovery, offer an alternate sign-in method. |
account-enabled | Suggested: re-enable Google sign-in and email recovery for that user. |
account-credential-change-required | Suggested: watch for suspicious activity and act accordingly. |
verification | Suggested: log that a test token arrived. This is the only event you can trigger on demand. |
token-revoked is the event that dictates your database schema
Most of these events identify the user and stop there. token-revoked is different: it identifies a specific token, and it does so without ever showing you the token.
The token subject identifier carries three fields. token_type — only refresh_token is supported. token_identifier_alg — either prefix or hash_base64_sha512_sha512. And token — which is either the first 16 characters of the token, or the double SHA-512 hash of it, depending on which algorithm the event used.
Google’s own guidance is to index your stored tokens by both of these possible values so a match is fast when the event arrives. That is a schema decision. A service that stored refresh tokens encrypted at rest with no prefix column and no double-hash column cannot answer the question the event is asking, and adding those columns later means re-deriving them across the entire token table.
This is also the point where the event stops being an abstract security nicety and starts touching the same operational surface as ordinary token lifecycle work — the reason a Google integration goes quiet without any code change. We cover the non-security version of that failure in Google deletes OAuth clients after six months of inactivity.
Why stream:update keeps returning 403
Registration is a single authorised POST to the RISC stream configuration API. It is also where the integration fails most often, and the error list reads like a checklist of assumptions people make:
- The delivery endpoint is not HTTPS. Google does not send RISC events to plain HTTP, even in testing.
- The endpoint’s domain is not in your project’s authorized domains. A receiver hosted on a vendor subdomain or a serverless default URL will be rejected until that domain is added.
- The calling identity is a user account rather than a service account. Stream management is service-account only.
- The service account lacks
roles/riscconfigs.admin. - The project has no OAuth client configured at all, which Google treats as evidence RISC will not be useful to you.
- Firebase is managing RISC for the project because Google Sign-In is enabled there — in which case a custom configuration is blocked until Google Sign-In is disabled in Firebase and an hour has passed.
None of these are bugs. Every one is a configuration or eligibility decision surfacing at the worst moment, which is the same pattern behind most consent-screen failures. The equivalent catalogue for the sign-in side is in Google OAuth consent screen errors and what each one really means.
Duplicate events are expected. Missed events are possible.
Cross-Account Protection will attempt to redeliver events it believes were not delivered, so your endpoint will sometimes see the same event more than once. If your response to an event is user-visible — force sign-out, credential reset, recovery-email lockout — repeated delivery becomes repeated disruption. The documented mitigation is de-duplicating on the jti claim, which is unique per event within the stream.
The inverse is the harder problem. Delivery is retried a limited number of times. If your receiver is down for an extended period, some events are permanently lost, and there is no backfill endpoint to catch up. A security posture that assumes the stream is complete is a security posture with a silent gap in it.
What a competent build actually has to get right
- Validate before you decode
Fetch the issuer and signing-key URI from Google’s RISC discovery document, match the key ID from the token header, verify the signature, the
iss, and thataudis one of your own client IDs. Validating after decoding is the mistake that turns a security feature into an attack surface. - Handle expiry correctly by not checking it
Security event tokens describe historical events and do not expire. A JWT library configured with default expiry checking will reject perfectly valid tokens, and the symptom looks like a signing problem.
- Return the right status codes
An unknown key ID or a malformed token is a 400. A valid token is a 202 — acknowledged — before you act on the event. Getting this inverted causes Google to retry tokens you already processed.
- Index tokens for both identifier algorithms
Prefix and double-SHA-512 lookups both need to be O(1) against your token store, decided before the first token is written.
- Store and delete under the RISC Terms
Google requires that received information is stored in a way that abides by the RISC Terms and deleted within a reasonable timeframe — including during testing. Your retention policy is part of the integration, not an afterthought.
Where these projects usually go wrong
- Subscribing to every event type, then implementing none of the required responses — which is worse than not subscribing, because the obligation now exists.
- Building the receiver on a staging domain that was never added to the project’s authorized domains, then debugging a 403 as if it were an auth-token problem.
- Treating RISC as a general account-activity feed and using the signals for analytics or product decisions, which the RISC Terms do not permit.
- Assuming Workspace users are covered. They are not — Google does not currently send security events for Workspace accounts.
- No
jtide-duplication, so a redeliveredaccount-disabledevent signs the same user out twice and generates a support ticket instead of a security win. - Refresh tokens stored without a prefix or double-hash index, making
token-revokedunactionable on arrival. - Requesting a custom scope list that omits
profileandemail, so the stream registers cleanly and then delivers nothing forever.
How this connects to verification
Cross-Account Protection is not part of OAuth verification and passing one has no bearing on the other. But they draw on the same evidence: what scopes you request, what user data you store, how long you keep it, and whether your privacy policy describes the real data flows. A team that has already assembled that material for a sensitive-scope review has most of what a RISC integration’s data-handling review needs. A team that has not is now assembling it twice. The verification side of that work is set out in our Google OAuth verification guide for sensitive and restricted scopes.
An honest note on outcomes. Whether Google enables an API, accepts terms on an organisation’s behalf, or approves a verification submission is decided by Google. Nothing here is promised or assured on your behalf. What preparation changes is the number of cycles — an integration where the scope list, the authorized domains, the service-account roles and the data-retention policy all describe the same product tends to resolve in far fewer rounds than one assembled reactively after a rejection. Our work is technical implementation support, review preparation, and policy-aligned guidance.
Every mechanic described above is taken from Google’s official Cross-Account Protection documentation, verified current in August 2026 (page last updated 22 March 2026). Google changes these details without notice — verify against the official page before you build around them.
Google’s official Cross-Account Protection RISC documentation covers security event tokens, receiver endpoints, event types, and acknowledgement requirements.
Google Cross-Account Protection RISC should be treated as a security event pipeline, not as a one-time webhook integration.
With Google Cross-Account Protection RISC, verify the security event token signature and issuer before changing a user’s session state.
Google Cross-Account Protection RISC receivers must tolerate duplicate delivery while preserving an audit trail for every token-revoked event.
Test Google Cross-Account Protection RISC with replayed, malformed, delayed, and unknown event payloads before production rollout.
A reliable Google Cross-Account Protection RISC implementation returns the required acknowledgement quickly and processes business logic asynchronously.
Keep Google Cross-Account Protection RISC event handling separate from the login request so revocation signals remain actionable.
Review Google Cross-Account Protection RISC logs regularly and alert on verification failures, unexpected event types, and acknowledgement timeouts.
Need Us to Get Your Google / YouTube API 100% Approved?
Stop losing weeks to OAuth verification back-and-forth and quota audits. With 500+ apps approved, we handle your entire submission from start to finish. You get 100% Approval or a 100% Refund — and for your complete safety, you can hire us directly through Upwork or Fiverr Escrow (or use the WhatsApp / Calendar buttons in the header & footer).
Chat on WhatsAppFrequently Asked Questions about Google OAuth verification
Why do apps get stuck in Google OAuth verification?
Typical blockers are unverified domains, privacy policies missing Google user data language, demo videos that don't show each scope in use, and requests for sensitive or restricted scopes the app could do without.
How long does it take if you handle it?
It usually takes ~2–3 days for preparation and submission, followed by the platform's review queue — typically 7–15 days (often faster on platforms like X, or longer depending on platform review volume and any follow-up rounds).
What if it still isn't approved?
We work on a 100% Approval or 100% Refund basis: if we can't get your valid use case approved, you get a full refund.
Is it safe to hire you?
Yes. You can hire us through Upwork or Fiverr, so your payment stays in Escrow and is only released when the work is delivered. We've been doing this for 10+ years, with 500+ apps approved and 10,000+ permissions granted.