Skip to main content

Google Slides

Proxy for the Google Slides v1 REST API — the entire API surface: create_presentation, get_presentation, get_page, get_page_thumbnail, and batch_update. Dual auth by design, like drive and calendar:

  • idp_passthrough mode for human users who want an agent to read or edit presentations they own. Each request carries the caller's own OAuth grant.
  • google_sa mode uses a Workspace service account with domain-wide delegation. For each call it impersonates the calling user, so the user does not link a Google account, but the call still needs a user token. The user is the token's sub when that is an email, otherwise the user's email, and its domain must match the Workspace domain setup field. No setup field names a user to impersonate. A client_credentials call has no user and gets 502 Upstream auth failed: No user identity in context; cannot impersonate (GoogleServiceAccountProvider.java). The connector sets no Google scopes for this mode, so the gateway asks Google for drive.readonly unless the resource's upstream auth carries a scopes list.

google_sa set up from the Admin Portal fails in 0.65.0. Every call gets 502 Upstream auth failed: No Google SA key configured, because the form stores the secret reference under sa_key_env (ConnectorV1Adapter.java:316-320) and the gateway reads it only from service_account_key_env (GoogleServiceAccountProvider.java:187-196). After you create the resource, rename the key with the admin API:

NAME=slides-sa   # the managed resource's name
curl -s -H "X-Admin-API-Key: $PBAC_ADMIN_API_KEY" "$PBAC_AS_URL/admin/api/managed-resources/$NAME" \
| jq '.upstreamAuth.service_account_key_env = .upstreamAuth.sa_key_env | del(.upstreamAuth.sa_key_env)' \
| curl -s -X PUT -H "X-Admin-API-Key: $PBAC_ADMIN_API_KEY" -H "Content-Type: application/json" \
"$PBAC_AS_URL/admin/api/managed-resources/$NAME" -d @-

To ask Google for other scopes, append | .upstreamAuth.scopes = ["<scope URL>"] to the jq filter. We ran this on a test instance with a stub token endpoint standing in for Google. After the rename, the gateway sent a signed JWT-bearer assertion with the calling user as sub and drive.readonly, or the scopes we set, as scope, and forwarded the token it got back to the upstream. A user outside the Workspace domain got 502 Email domain '...' does not match configured domain. We have not run a google_sa call through to Google.

Overview​

Typical uses:

  • An agent reads a deck's structure or renders a slide thumbnail to describe it (get_presentation, get_page, get_page_thumbnail).
  • A generation workflow creates a deck and adds slides / inserts text (create_presentation, then batch_update with createSlide / insertText).

Two upstream-shape notes specific to Slides:

  • No list endpoint. The Slides API can't enumerate presentations; discover presentation IDs via the Google Drive connector (filter on mimeType = 'application/vnd.google-apps.presentation'), then operate on the ID here.
  • Mutations and deletes are batch_update. Adding/deleting slides and page elements (createSlide, deleteObject, insertText) are request objects on batch_update; deleting an entire presentation file is the Drive connector's job.

Default policy​

The connector ships connectors/identos.google-slides/policy/slides.rego (package pbac.connectors.identos.google_slides), which holds no rules.

The IdP-routing obligation that earlier releases documented here guarded on input.connector, a field no entrypoint sets, so it never fired, and it was removed. In idp_passthrough mode the gateway enforces the Google link itself. Before it forwards a call it checks for a usable linked Google token, and without one it answers 401 with "error": "idp_link_required" and a link_url.

Blocked and read-only presentations​

Blocking a specific presentation is operator config on the general file-access control, not a rule in this connector. An identity source matches a presentation by its own id: ids in blocked are denied on reads and writes, ids in write_blocked are denied on writes only (batch_update), so reads still work. See File access control below for the shape — an identity source pools with any label or location source governing the same connector.

File access control​

Presentations can be gated by Drive Labels and/or by folder/shared-drive location — a presentation is returnable via get_presentation if it matches any governing source's approval (an approved label or an approved folder), and denied if it matches any source's blocked (pooled OR, deny-wins). This is configured through the shared file_access operator control, used across all Google file connectors (Docs, Sheets, Slides, Drive). Full mechanics (the pooled predicate, OR-combine and deny-wins, fail-closed rules) live in the File Access Control guide; for getting label/folder IDs and the required OAuth scopes, see the Google file access setup guide.

Configuration uses a two-level model:

  1. Define a policy per source — under pbac.operator.controls.file_access.sources, each source declares a type (label, location, or identity — the resource's own id), a required allowlist (any-of; file must match ≥1), a blocked denylist (file withheld if it matches any — always wins), and an optional write_blocked denylist that applies to mutating calls only. Approving a whole folder is a location source with the folder ID in required (Google Drive does not allow labels on folders):
curl -X PUT "http://localhost:8080/admin/api/policy-data/by-key?dataKey=pbac.operator.controls.file_access" \
-H "X-Admin-API-Key: $PBAC_ADMIN_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"dataKey": "pbac.operator.controls.file_access",
"payload": {
"sources": {
"google-drive-labels": {
"type": "label",
"required": ["<approved-label-id>"],
"blocked": ["<restricted-label-id>"]
}
},
"governed": {
"urn:connector:identos:google-slides": ["google-drive-labels"]
}
}
}'

The call replaces the whole row, so keep the sources and governed entries of every other connector you govern in the payload.

  1. Activate per connector — under governed, list (as an array) which sources govern each connector's resource type; all listed sources pool into one OR-of-approvals, deny-wins decision — a file is returnable if it matches any source's required and withheld if it matches any source's blocked. Omitting a connector leaves it ungoverned (inert; no check). Once a source is configured and a connector is governed by it, enforcement is fail-closed: reads that cannot verify the file's values are denied (403).

The control resolves presentation IDs from tool invocations to fetch labels/location; file and scope requirements are documented in the spec at docs/superpowers/specs/2026-08-11-general-file-access-control-design.md.

Scope model​

ScopeUsed for
PBAC scopes (internal)slides:read, slides:writeRoute authorization
Upstream OAuth scopesopenid, userinfo.email, presentations, drive.metadata.readonly, drive.labels.readonly, drive.labelsGoogle-side grants the user consents to (idp_passthrough mode). google_sa mode sets none and gets drive.readonly

See Google Workspace: multi-connector setup for how slides' scopes compose with drive, gmail, and calendar on a single Google IdP.

Manifest reference​

  • ID: identos.google-slides
  • Version: 1.4.0
  • Resource type: urn:connector:identos:google-slides

Supported auth modes​

TypeDetails
idp_passthroughrequires IdP google
google_sasetup fields: sa_key_env, domain

Setup fields​

IDLabelDefaultSecret?Notes
base_urlAPI base URLhttps://slides.googleapis.comno—
upstream_auth.typeAuthenticationidp_passthroughnoidp_passthrough forwards each user's own Google OAuth token (recommended). google_sa uses a Workspace service account with domain-wide delegation impersonating a fixed user.
sa_key_envService account key—yesPick a secret containing the service-account JSON. Required only for the google_sa auth mode. / shown when upstream_auth.type == 'google_sa'
domainWorkspace domain—noplaceholder: example.com / Required only for the google_sa auth mode. / shown when upstream_auth.type == 'google_sa'

Scopes​

Scope
slides:read
slides:write

Routes​

MethodPatternScopeResource template
POST/v1/presentationsslides:write—
GET/v1/presentations/{presentation_id}slides:readslides://{{presentation_id}}
GET/v1/presentations/{presentation_id}/pages/{page_object_id}slides:readslides://{{presentation_id}}
GET/v1/presentations/{presentation_id}/pages/{page_object_id}/thumbnailslides:readslides://{{presentation_id}}
POST/v1/presentations/{presentation_id}:batchUpdateslides:writeslides://{{presentation_id}}

MCP tools​

NameScopeDescription
create_presentationslides:writeCreate a new presentation. Pass {"title": "..."}. Add slides afterward with batch_update.
get_presentationslides:readGet a presentation's full structure (slides, layouts, masters, page elements).
get_pageslides:readGet a single page (slide) of a presentation by its object ID.
get_page_thumbnailslides:readGet a rendered thumbnail image URL for a single page (slide).
batch_updateslides:writeApply one or more updates (createSlide, deleteObject, insertText, replaceAllText, image/shape ops, …) via Slides Request objects. This is also how you DELETE slides/objects.