Google Cloud credentials, the refresh token, OAuth verification, and reading Meet artifacts, attendance, and exports. Part of the Google Meet plugin guide.

OAuth and preflight

OAuth is optional for creating a Meet link, because googlemeet create can fall back to browser automation. Configure OAuth for official API create, space resolution, or Meet Media API preflight. Chrome/Chrome-node joins never depend on OAuth; they use a signed-in Chrome profile, the host's native virtual-audio backend, and (for chrome-node) a connected node either way.

Create Google credentials

In Google Cloud Console:

Create or select a project

Enable the Google Meet REST API

Configure the OAuth consent screen

Internal is simplest for a Google Workspace organization. External works for personal/test setups; while the app is in Testing, add each Google account that will authorize it as a test user.

Add the requested scopes

  • https://www.googleapis.com/auth/meetings.space.created
  • https://www.googleapis.com/auth/meetings.space.readonly
  • https://www.googleapis.com/auth/meetings.space.settings
  • https://www.googleapis.com/auth/meetings.conference.media.readonly
  • https://www.googleapis.com/auth/calendar.events.readonly (Calendar lookup)
  • https://www.googleapis.com/auth/drive.meet.readonly (transcript/smart-note document body export)

Create an OAuth client ID

Application type Web application. Authorized redirect URI:

http://localhost:8085/oauth2callback

Copy the client ID and client secret

meetings.space.created is required by spaces.create. meetings.space.readonly resolves Meet URLs/codes to spaces. meetings.space.settings lets Apus pass SpaceConfig settings such as accessType during API room creation. meetings.conference.media.readonly is for Meet Media API preflight and media work; Google may require Developer Preview enrollment for actual Media API use. calendar.events.readonly is only needed for --today/--event calendar lookup. drive.meet.readonly is only needed for --include-doc-bodies export. If you only need browser-based Chrome joins, skip OAuth entirely.

Mint the refresh token

Configure oauth.clientId and optionally oauth.clientSecret (or pass them as environment variables), then run:

apus googlemeet auth login --json

This runs a PKCE flow with a localhost callback on http://localhost:8085/oauth2callback, and prints an oauth config block with a refresh token. Add --manual for a copy/paste flow when the browser cannot reach the local callback:

APUS_GOOGLE_MEET_CLIENT_ID="your-client-id" \
APUS_GOOGLE_MEET_CLIENT_SECRET="your-client-secret" \
apus googlemeet auth login --json --manual

JSON output:

{
  "oauth": {
    "clientId": "your-client-id",
    "clientSecret": "your-client-secret",
    "refreshToken": "refresh-token",
    "accessToken": "access-token",
    "expiresAt": 1770000000000
  },
  "scope": "..."
}

Store the oauth object under the plugin config:

{
  plugins: {
    entries: {
      "google-meet": {
        enabled: true,
        config: {
          oauth: {
            clientId: "your-client-id",
            clientSecret: "your-client-secret",
            refreshToken: "refresh-token",
          },
        },
      },
    },
  },
}

Prefer environment variables when you do not want the refresh token in config; config is resolved first, then environment as fallback. If you authenticated before meeting creation, calendar lookup, or document-body export support existed, rerun apus googlemeet auth login --json so the refresh token covers the current scope set.

Verify OAuth with doctor

apus googlemeet doctor --oauth --json

This checks OAuth config exists and the refresh token can mint an access token, without loading the Chrome runtime or requiring a connected node. The report includes only status fields (ok, configured, tokenSource, expiresAt, check messages) and never prints the access token, refresh token, or client secret.

Check Meaning
oauth-config oauth.clientId plus oauth.refreshToken, or a cached access token, is present
oauth-token The cached access token is still valid, or the refresh token minted a new one
meet-spaces-get Optional --meeting check resolved an existing Meet space
meet-spaces-create Optional --create-space check created a new Meet space

Prove Meet API enablement and spaces.create scope with the side-effecting create check:

apus googlemeet doctor --oauth --create-space --json

Prove read access to an existing space:

apus googlemeet doctor --oauth --meeting https://meet.google.com/abc-defg-hij --json
apus googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij

A 403 from these checks usually means the Meet REST API is disabled, the refresh token is missing the required scope, or the Google account cannot access that space. A refresh-token error means rerun apus googlemeet auth login --json and store the new oauth block.

No OAuth is needed for the browser fallback; Google auth there comes from the signed-in Chrome profile on the selected node, not Apus config.

These environment variables are accepted as fallbacks:

Resolve, preflight, and read artifacts

apus googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij
apus googlemeet preflight --meeting https://meet.google.com/abc-defg-hij

After Meet has created conference records:

apus googlemeet artifacts --meeting https://meet.google.com/abc-defg-hij
apus googlemeet attendance --meeting https://meet.google.com/abc-defg-hij
apus googlemeet export --meeting https://meet.google.com/abc-defg-hij --output ./meet-export

With --meeting, artifacts and attendance use the latest conference record by default; pass --all-conference-records for every retained record.

Calendar lookup resolves the meeting URL from Google Calendar before reading artifacts (requires a refresh token that includes the Calendar events readonly scope):

apus googlemeet latest --today
apus googlemeet calendar-events --today --json
apus googlemeet artifacts --event "Weekly sync"
apus googlemeet attendance --today --format csv --output attendance.csv

--today searches today's primary calendar for an event with a Meet link; --event <query> searches matching event text; --calendar <id> targets a non-primary calendar. calendar-events previews matching events and marks which one latest/artifacts/attendance/export will choose.

If you already know the conference record id, address it directly:

apus googlemeet latest --meeting https://meet.google.com/abc-defg-hij
apus googlemeet artifacts --conference-record conferenceRecords/abc123 --json
apus googlemeet attendance --conference-record conferenceRecords/abc123 --json

Close the room for an API-created space:

apus googlemeet end-active-conference https://meet.google.com/abc-defg-hij

Calls spaces.endActiveConference and requires OAuth with the meetings.space.created scope for a space the authorized account can manage. Accepts a Meet URL, meeting code, or spaces/{id} and resolves it to the API space resource first. This is separate from googlemeet leave: leave stops Apus's local/session participation; end-active-conference asks Google Meet to end the active conference for the space.

Write a readable report:

apus googlemeet artifacts --conference-record conferenceRecords/abc123 \
  --format markdown --output meet-artifacts.md
apus googlemeet attendance --conference-record conferenceRecords/abc123 \
  --format csv --output meet-attendance.csv
apus googlemeet export --conference-record conferenceRecords/abc123 \
  --include-doc-bodies --zip --output meet-export
apus googlemeet export --conference-record conferenceRecords/abc123 \
  --include-doc-bodies --dry-run

For artifacts and attendance, --output <path> writes the selected format, including the default summary, to a file. Without --output, the report goes to stdout.

artifacts returns conference record metadata plus participant, recording, transcript, structured transcript-entry, and smart-note resource metadata when Google exposes it. --no-transcript-entries skips entry lookup for large meetings. attendance expands participants into participant-session rows with first/last seen times, total session duration, late/early-leave flags, and duplicate participant resources merged by signed-in user or display name; --no-merge-duplicates keeps raw resources separate, --late-after-minutes/--early-before-minutes tune the thresholds.

export writes a folder with summary.md, attendance.csv, transcript.md, artifacts.json, attendance.json, and manifest.json. manifest.json records the chosen input, export options, conference records, output files, counts, token source, any Calendar event used, and partial-retrieval warnings. --zip also writes a portable archive next to the folder. --include-doc-bodies exports linked transcript/smart-note Google Docs text through Drive files.export (requires the Drive Meet readonly scope); without it, exports include Meet metadata and structured transcript entries only. A partial artifact failure (smart-note listing, transcript-entry, or document-body error) keeps the warning in the summary/manifest instead of failing the whole export. --dry-run fetches the same data and prints the manifest JSON without creating the folder or ZIP.

Agents use the same actions through the google_meet tool (export, create with accessType, end_active_conference, test_listen); see Tool.

Live smoke test

pnpm test:live requires a source checkout of the Apus repo; the apus googlemeet commands below run from any install.

APUS_LIVE_TEST=1 \
APUS_GOOGLE_MEET_LIVE_MEETING=https://meet.google.com/abc-defg-hij \
pnpm test:live -- extensions/google-meet/google-meet.live.test.ts
apus googlemeet setup --transport chrome-node --mode transcribe
apus googlemeet test-listen https://meet.google.com/abc-defg-hij --transport chrome-node --timeout-ms 30000
Variable Purpose
APUS_LIVE_TEST=1 Enables guarded live tests
APUS_GOOGLE_MEET_LIVE_MEETING Retained Meet URL, code, or spaces/{id}
APUS_GOOGLE_MEET_CLIENT_ID / GOOGLE_MEET_CLIENT_ID OAuth client id
APUS_GOOGLE_MEET_REFRESH_TOKEN / GOOGLE_MEET_REFRESH_TOKEN Refresh token
APUS_GOOGLE_MEET_CLIENT_SECRET, APUS_GOOGLE_MEET_ACCESS_TOKEN, APUS_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT Optional; same fallback names without the APUS_ prefix also work

The base artifact/attendance smoke needs meetings.space.readonly and meetings.conference.media.readonly. Calendar lookup needs calendar.events.readonly. Drive document-body export needs drive.meet.readonly.

Create examples

apus googlemeet create

Prints the new meeting URI, source, and join session. With OAuth it uses the Meet API; without it, the pinned Chrome node's signed-in profile. Browser fallback JSON:

{
  "source": "browser",
  "meetingUri": "https://meet.google.com/abc-defg-hij",
  "joined": true,
  "browser": {
    "nodeId": "ba0f4e4bc...",
    "targetId": "tab-1"
  },
  "join": {
    "session": {
      "id": "meet_...",
      "url": "https://meet.google.com/abc-defg-hij"
    }
  }
}

If the browser fallback hits Google login or a Meet permission blocker first, google_meet returns structured details instead of a plain string:

{
  "source": "browser",
  "error": "google-login-required: Sign in to Google in the Apus browser profile, then retry meeting creation.",
  "manualAction": {
    "reason": "google-login-required",
    "message": "Sign in to Google in the Apus browser profile, then retry meeting creation."
  },
  "browser": {
    "nodeId": "ba0f4e4bc...",
    "targetId": "tab-1",
    "browserUrl": "https://accounts.google.com/signin",
    "browserTitle": "Sign in - Google Accounts"
  }
}

API create JSON:

{
  "source": "api",
  "meetingUri": "https://meet.google.com/abc-defg-hij",
  "joined": true,
  "space": {
    "name": "spaces/abc-defg-hij",
    "meetingCode": "abc-defg-hij",
    "meetingUri": "https://meet.google.com/abc-defg-hij"
  },
  "join": {
    "session": {
      "id": "meet_...",
      "url": "https://meet.google.com/abc-defg-hij"
    }
  }
}

Creating joins by default, but Chrome/Chrome-node still needs a signed-in Google profile to join through the browser; if signed out, Apus returns manualAction or a browser fallback error and asks the operator to finish Google login before retrying.

Set preview.enrollmentAcknowledged: true only after confirming your Cloud project, OAuth principal, and meeting participants are enrolled in the Google Workspace Developer Preview Program for Meet media APIs.