85 lines
5.2 KiB
Markdown
85 lines
5.2 KiB
Markdown
# Google access through a credential broker
|
|
|
|
A credential broker is a server of yours that holds the Google service-account keys, the Cloud project facts and the
|
|
Play permission grants. With one configured, storebound keeps no Google key on the machine: it asks the broker for a
|
|
short-lived access token for each Google API call and reads the package's Play permissions from it before a command
|
|
writes anything. The local key (`PLAY_SERVICE_ACCOUNT`) keeps working and is the fallback.
|
|
|
|
## Setup
|
|
|
|
`~/.storebound/broker.json`:
|
|
|
|
```json
|
|
{
|
|
"url": "https://broker.example.com",
|
|
"apiKeyFile": "~/.storebound/broker.key",
|
|
"account": "play-publisher@example.com"
|
|
}
|
|
```
|
|
|
|
- `url`: the broker's base URL. Only `https://` (plain `http://` only for `localhost`, a local test broker).
|
|
- `apiKeyFile`: a file with one scoped API key on one line, with the scopes `google:read` and `google:token`. On macOS
|
|
and Linux it must be `chmod 600`: storebound refuses a key file that the group or others can read. Default:
|
|
`broker.key` next to `broker.json`. The key is never printed, never written into a config or a log.
|
|
- `account` (optional): the service account e-mail the broker mints tokens for. A credential profile or the project
|
|
can name its own with `PLAY_SERVICE_ACCOUNT_EMAIL` (env, `~/.storebound/credentials/<profile>.json`,
|
|
`.storebound/credentials.json`); without either, the `client_email` of a local key is used, and for Play commands
|
|
the account the broker names for the package.
|
|
|
|
Overrides: `STOREBOUND_BROKER_URL`, `STOREBOUND_BROKER_KEY_FILE` (env wins over the file), `STOREBOUND_BROKER_CONFIG`
|
|
(another broker.json). Off: `STOREBOUND_BROKER=off` for one run, `"broker": false` in a credential profile (that profile
|
|
keeps its key file), or env `STOREBOUND_PROFILE_<NAME>_BROKER=off`.
|
|
|
|
## What storebound calls
|
|
|
|
| call | when |
|
|
|---|---|
|
|
| `POST /api/google/token` `{ "account", "scopes": ["androidpublisher"] }` -> `{ "accessToken", "expiresAt" }` | before Google calls. Kept in memory until 5 minutes before `expiresAt`; parallel calls share one request |
|
|
| `GET /api/google/play/<package>/storebound` | `storebound validate`, the preflight of Play write commands, `apps check` and the desktop's Accounts view |
|
|
|
|
Scopes: `androidpublisher` for the Play Developer API, `cloud-platform.read-only` for Play statistics exports and Play
|
|
Games configuration reads. The broker hands out no scope for the Play Developer Reporting API (vitals, the app list of
|
|
`apps list`) or for Play Games configuration writes: those use the local key, and say so when there is none.
|
|
|
|
## Fallback and failures
|
|
|
|
- Broker not configured: the local key, as before.
|
|
- Broker not answering (network error, timeout, 5xx) or not knowing the account (400 / 404 on a token): the local key,
|
|
with one warning per run. No local key: the error names the broker.
|
|
- Broker refusing the API key (401 / 403): storebound stops with "the key lacks google:token" and does not retry or
|
|
fall back. Give the key its scopes on the broker.
|
|
- A package the broker does not know (404 on `/storebound`): a warning to register it there. It is not a missing
|
|
Play access; the command still runs and Google answers for itself.
|
|
|
|
## Permission checks
|
|
|
|
The broker's answer lists the service account's Play permissions for the package and the APIs enabled in its Cloud
|
|
projects. Before a Play command writes, storebound compares them with what the command needs and stops before any
|
|
Play call, naming the exact permission or API and the link to fix it:
|
|
|
|
| work | Play permission | commands |
|
|
|---|---|---|
|
|
| uploads, releases, rollouts | `CAN_MANAGE_TRACK_APKS` | `play upload`, `play release`, `play rollout`, `play share` |
|
|
| store listing and images | `CAN_MANAGE_PUBLIC_LISTING` | `play listing`, `play images` |
|
|
| products and subscriptions | `CAN_MANAGE_ORDERS` | `play products`, `play subscriptions` |
|
|
| Data safety, app content | `CAN_MANAGE_APP_CONTENT` | `play data-safety` |
|
|
| review replies | `CAN_REPLY_TO_REVIEWS` | (listed in the checks) |
|
|
| Play Games Services | API `gamesconfiguration.googleapis.com` | `play games` |
|
|
|
|
Every Play call also needs `androidpublisher.googleapis.com` enabled. A dry run (`--dry`) and reads only warn.
|
|
`storebound validate` reports the same gaps as blockers, the permissions and APIs the broker lists, and SDK config
|
|
files (`google-services.json`, `GoogleService-Info.plist`) the broker reports as drifted or whose sha256 differs from
|
|
the repo's copy.
|
|
|
|
When Google itself answers 403 `SERVICE_DISABLED` or `PERMISSION_DENIED`, the error names the API (with its enable
|
|
link) or the missing app access (with the Users and permissions link), adds what the broker lists for the package, and
|
|
is never retried.
|
|
|
|
## Where it shows
|
|
|
|
- `storebound doctor`: `Play: tokens from the credential broker <url> for p***@...` (or the local key, and why the
|
|
broker is not usable). `--json`: `play.source` is `"broker"` or `"file"`.
|
|
- `storebound accounts`: a "Play via" column (credential broker / key file) per profile.
|
|
- `storebound validate --json` (and MCP `validate`): `credentials.play.source`.
|
|
- `storebound apps check --store play --json` and the desktop's Accounts view: `source` and, per Play app of the
|
|
machine, the permissions and APIs the broker lists and what is missing.
|