Security
A checklist for hardening your integration, followed by the reasoning behind the load-bearing items.
| Requirement | What it means |
|---|---|
| HTTPS / TLS only | All traffic over TLS 1.2+. gRPC channels require TLS in production. |
Protect the client_secret | Store the External API secret in environment variables or a secret manager — never in source. |
Validate state | Check the state parameter on every callback (PKCE itself handles CSRF). |
| Fresh PKCE per login | Generate a new code_verifier for every authorization request. |
| Keep tokens server-side | Never expose access or refresh tokens to browser JavaScript. |
| Encrypt refresh tokens | Encrypt them at rest in your database. |
| No sensitive logging | Never log tokens or secrets. |
| Persist the event cursor | Store last_event_id durably so an event stream resumes reliably. |
Tokens
Treat the access token as opaque — do not parse or verify it yourself; call UserInfo for user data. Store refresh tokens encrypted, scoped to a session rather than a user, so a logout can discard them. Refresh proactively, before the one-hour access-token expiry.
Credentials are separate
The PKCE login client and the External API client are different registrations with different secrets and different blast radii. A leaked login client is low-impact (PKCE means there's no usable secret); a leaked External API client_secret lets someone send on your behalf — guard it accordingly, and rotate it if exposed.
Rate limits
The External API enforces a per-app rate limit and a monthly message quota. Handle RESOURCE_EXHAUSTED by backing off with the retry-after-ms hint rather than hammering the endpoint — the exact limits per plan are in the Messaging reference.