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.createdhttps://www.googleapis.com/auth/meetings.space.readonlyhttps://www.googleapis.com/auth/meetings.space.settingshttps://www.googleapis.com/auth/meetings.conference.media.readonlyhttps://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:
APUS_GOOGLE_MEET_CLIENT_IDorGOOGLE_MEET_CLIENT_IDAPUS_GOOGLE_MEET_CLIENT_SECRETorGOOGLE_MEET_CLIENT_SECRETAPUS_GOOGLE_MEET_REFRESH_TOKENorGOOGLE_MEET_REFRESH_TOKENAPUS_GOOGLE_MEET_ACCESS_TOKENorGOOGLE_MEET_ACCESS_TOKENAPUS_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_ATorGOOGLE_MEET_ACCESS_TOKEN_EXPIRES_ATAPUS_GOOGLE_MEET_DEFAULT_MEETINGorGOOGLE_MEET_DEFAULT_MEETINGAPUS_GOOGLE_MEET_PREVIEW_ACKorGOOGLE_MEET_PREVIEW_ACK
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.