Call the API

The payoff is deliberately boring. The Storage API sees ci-deployer@authlab-lab.iam.gserviceaccount.com and checks its IAM roles like any other caller; it never saw the OIDC token, or that federation happened at all.

Call sequence

runner forgejo ci forgejo forgejo.authlab.app STS sts.googleapis.com iam credentials iamcredentials.googleapis.com cloud storage storage.googleapis.com step 1 GET /idtoken 200 · oidc jwt step 2 POST /token GET discovery GET JWKS 200 · federated step 3 POST :generateAccessToken 200 · sa token step 4 1 GET /storage/v1/b 2 200 · buckets
  • a plain authenticated call with the service account's token
  • the Storage API never sees the OIDC token, or that federation happened at all
  • GCP checks the service account's IAM roles, like any other caller, and returns the buckets
request GET
curl 'https://storage.googleapis.com/storage/v1/b?project=authlab-lab' \
    -H 'Authorization: Bearer ya29.c.SYNTHETIC-sa-access-token-not-valid-for-use'
response 200 OK
{
  "kind": "storage#buckets",
  "items": [
    {
      "kind": "storage#bucket",
      "name": "authlab-lab-artifacts",
      "projectNumber": "1234567890",
      "location": "US",
      "storageClass": "STANDARD"
    }
  ]
}

Who GCP sees

ci-deployer@authlab-lab.iam.gserviceaccount.com

Compare with the workforce track, where the same class of token meets a very different validator.