Automated Cruise Auth Refresh
Fully automates authcli refresh including the Google → Okta → Microsoft SSO → Duo
browser flow. Requires user interaction only for Microsoft MFA number matching.
Prerequisites
Secret file at
~/.cruise-google-creds(mode 600), JSON format:{ "email": "user@gm.com", "password": "<okta_password>", "ms_password": "<microsoft_ad_password>", "gcp_email": "user@getcruise.com" }Field Used for Required emailOkta login (cruise.okta.com) Yes passwordOkta password Yes ms_passwordMicrosoft Azure AD password (login.microsoftonline.com). Falls back to passwordif absent.Recommended gcp_emailGoogle account for GCP re-auth (accounts.google.com). Falls back to emailif absent.Recommended If this file does not exist, tell the user to create it and STOP.
Playwright + xvfb installed:
cd ~/.cursor/scripts && npm install playwright npx playwright install-deps chromium sudo apt-get install -y xvfb # for headed mode on headless VMsPlaywright is installed in
~/.cursor/scripts/node_modules/. Google blocks headless Chrome;xvfblets us run headed mode on a headless VM.Scripts at
~/.cursor/scripts/:cruise-auth-refresh.exp— expect script that drivesauthcli refreshcruise-auth-browser.mjs— Playwright script that completes the SSO flow
When to Trigger
gcloud auth application-default print-access-tokenreturns "Reauthentication" or errorauthcli statusshows any credential as non-VALID- Any command fails with
401,credentials,Permission denied,RefreshError,Reauthentication,access token, orinsufficient authentication scopes - Google Drive/Docs API returns
403 insufficient scopes(usegcloud-adcmode)
Other skills/workflows should call this skill whenever they detect auth-related errors rather than asking the user to re-auth manually. See "Cross-Referencing from Other Skills" at the bottom.
Auth Flow Architecture
There are two distinct flows depending on what authcli refresh needs:
GCP re-auth flow (most common after hours of inactivity)
authcli refresh -no-launch-browser -re-auth gcp
→ prints Google OAuth URL (accounts.google.com)
Browser automation (xvfb + Playwright):
1. Navigate to Google OAuth URL
2. Fill GCP email (gcp_email) → Next
3. Google redirects to Okta SAML (cruise.okta.com)
4. Okta auto-submits or fills email → redirects to Microsoft SSO
5. Fill Microsoft password (ms_password) on login.microsoftonline.com
6. Handle "Stay signed in?" → Yes
7. ★ Microsoft MFA: display 2-digit number for user to enter in Authenticator
8. Okta redirects to Duo Security (duosecurity.com)
9. Auto-click "Skip for now" on Duo Desktop check
10. Duo auto-approves (no user action if device is remembered)
11. Google consent: auto-click "Continue" (may need 2 clicks)
12. Extract auth code from sdk.cloud.google.com/authcode.html
Expect script reads code and feeds it to authcli stdin.
App re-auth flow (Okta SSO)
authcli refresh -no-launch-browser [-re-auth all]
→ prints Okta OAuth URL (cruise.okta.com)
Browser automation:
1-6. Same Okta → Microsoft → MFA → Duo flow as above
7. Redirected to iop.robot.car/cli_callback?code=...
8. Extract code from callback URL
What requires user interaction
| Step | Automated? | User action needed |
|---|---|---|
| Google email/password | Yes | None |
| Okta email | Yes | None |
| Microsoft password | Yes | None |
| Microsoft MFA (number matching) | Partially | Enter displayed number in Authenticator app |
| Duo Security | Yes (Skip + auto-approve) | None |
| Google consent | Yes | None |
Microsoft MFA is the only step requiring user action. The script displays the 2-digit number in the terminal output. The operator (human or AI agent) must read this number and tell the user to enter it in their Microsoft Authenticator app.
Flow
Step 0: Check if refresh is actually needed
authcli status 2>&1
If ALL rows show VALID, auth is fine. Skip the rest.
Step 1: Read credentials from secret file
cat ~/.cruise-google-creds
Parse the JSON. Store in memory for later.
Step 2: Start expect script in background
~/.cursor/scripts/cruise-auth-refresh.exp
Run in a background terminal (block_until_ms: 0). The expect script will:
- Spawn
authcli refresh -no-launch-browser - Auto-answer "y" to prompts
- Write the OAuth URL to
/tmp/cruise-auth-url.txt - Wait up to 960 seconds for the code at
/tmp/cruise-auth-code.txt
To force re-authentication (even when tokens are valid):
~/.cursor/scripts/cruise-auth-refresh.exp gcp # GCP only
~/.cursor/scripts/cruise-auth-refresh.exp all # all tokens
~/.cursor/scripts/cruise-auth-refresh.exp gcloud-adc # GCP ADC with Drive/Docs/Sheets scopes
The gcloud-adc mode runs gcloud auth application-default login with Drive, Docs,
Sheets, and Cloud Platform scopes. Use this when publishing Google Docs or accessing
Drive API. The browser flow is identical to GCP re-auth.
Step 3: Poll for the OAuth URL
Check /tmp/cruise-auth-status.txt every 5 seconds:
STARTED→ still initializingURL_CAPTURED→ URL is ready at/tmp/cruise-auth-url.txtWAITING_FOR_CODE→ URL captured AND verification code prompt reachedSUCCESS→ auth refreshed silently (no browser needed). Done!FAILED:*→ authcli failed. Check the terminal output.
If SUCCESS appears without URL_CAPTURED, skip browser steps.
Step 4: Run Playwright browser automation via xvfb
IMPORTANT: Must use xvfb-run for headed mode. Google blocks headless Chrome.
cd ~/.cursor/scripts && \
XVFB=1 xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" \
node cruise-auth-browser.mjs 2>&1
Run in a background terminal (block_until_ms: 0) so you can monitor output.
The script will:
- Read credentials from
~/.cruise-google-creds - Read the OAuth URL from
/tmp/cruise-auth-url.txt - Navigate through Google → Okta → Microsoft → MFA → Duo → consent
- Write screenshots to
/tmp/cruise-auth-*.pngat each step - Extract the authorization code and write to
/tmp/cruise-auth-code.txt
Exit codes:
- 0: Success, code written
- 1: General error
- 2: Account locked or wrong password
- 3: MFA/Duo timeout (user didn't approve in 900s)
- 4: Timeout waiting for final redirect
Step 4a: Handle Microsoft MFA
When the script reaches Microsoft MFA, it prints the number to the terminal:
========================================
MFA NUMBER: 78
Enter this in Microsoft Authenticator
========================================
You MUST monitor the browser terminal output for this number and immediately tell the user to enter it in their Microsoft Authenticator app. The MFA times out after 900s (15 minutes).
To find the number:
- Read the browser terminal output file
- Look for
MFA NUMBER:in the output - Also check the screenshot at
/tmp/cruise-auth-05-mfa-page.png
After the user approves MFA, the script automatically handles Duo and Google consent.
Step 5: Wait for expect script to complete
Poll /tmp/cruise-auth-status.txt:
CODE_SENT→ expect sent the code to authcliSUCCESS→ done! Auth refreshed.FAILED:*→ something went wrong after code submission
Step 6: Verify
authcli status 2>&1
gcloud auth application-default print-access-token 2>&1 | head -1
Both should show valid credentials.
Fallback: Manual completion
If browser automation fails (account lockout, repeated MFA timeout, CAPTCHA):
- Read
/tmp/cruise-auth-url.txtand print the OAuth URL for the user - Tell the user: "Please open this URL in your browser and complete sign-in. Then paste the verification code here."
- When the user provides the code, write it to
/tmp/cruise-auth-code.txt - The expect script will pick it up and feed it to authcli
- Verify with
authcli status
SSO Flow Details
The SSO flow goes through multiple identity providers:
- Google (
accounts.google.com): GCP OAuth, acceptsgcp_email. For managed accounts, redirects to SAML/Okta. - Okta (
cruise.okta.com): Cruise's IdP, acceptsemail. Auto-redirects to Microsoft. - Microsoft Azure AD (
login.microsoftonline.com): GM's corporate SSO, acceptsms_password. The Okta email maps to an internal GM account (e.g.,user@gm.com→xxxxx@nam.corp.gm.com). - Microsoft MFA: Number matching via Microsoft Authenticator app. Required on unrecognized devices (Linux VMs). Not required on enrolled devices (e.g., your MacBook).
- Duo Security (
duosecurity.com): Cruise's second factor. "Skip for now" bypasses the Desktop check; auto-approves if device was previously remembered. - Google Consent (
accounts.google.com/signin/oauth/id): May require clicking "Continue" once or twice. Grants Google Cloud SDK access. - Callback:
iop.robot.car/cli_callback?code=...(Okta flow) orsdk.cloud.google.com/authcode.html(Google flow). Code is extracted from URL/page.
Why MFA is required every time on Linux VMs
Microsoft's Conditional Access Policies trigger MFA based on device enrollment.
Your MacBook is enrolled as a trusted device (via Company Portal / Intune), so MFA is
skipped there. A Linux VM is not enrolled and cannot be — Microsoft requires MFA
every single time on unmanaged devices. The persistent browser profile
(~/.cruise-browser-profile) caches cookies/sessions for Okta and Duo (reducing their
prompts), but cannot bypass Microsoft MFA. Plan for MFA on every auth refresh.
Cleanup / Reset
To clear all state and start fresh:
rm -rf ~/.cruise-browser-profile
rm -f /tmp/cruise-auth-url.txt /tmp/cruise-auth-code.txt /tmp/cruise-auth-status.txt /tmp/cruise-auth-*.png
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
~/.cruise-google-creds missing |
First-time setup | Tell user to create it |
| Playwright not installed | Missing npm package | cd ~/.cursor/scripts && npm install playwright |
libatk-1.0.so.0: cannot open |
Missing system deps | npx playwright install-deps chromium |
xvfb-run: not found |
Missing xvfb | sudo apt-get install -y xvfb |
| Google "Couldn't sign you in" | Headless browser detected | Must use xvfb-run for headed mode |
| Google "Couldn't find your Google Account" | Wrong email for GCP | Set gcp_email in creds file |
| Account temporarily locked | Wrong Microsoft password | Wait 15-30 min; update ms_password in creds |
| MFA timeout | User didn't enter number in time | Retry; tell user the number immediately |
| Duo "Skip for now" not clicked | Timing issue (page loads after check) | Fixed: script retries in wait loop |
| Google consent "Continue" not clicked | Multiple consent pages | Fixed: polling loop clicks Continue |
Execution context was destroyed |
Navigation race during rapid redirects | Fixed: caught and recovered |
| Script exits with code 3 | MFA or Duo timeout (900s) | Retry; ensure user has Authenticator ready |
Autonomy
- Steps 0-6: fully autonomous except for MFA number relay
- MFA step: read the number from terminal output, tell the user immediately
- Duo: fully automatic (no user action)
- Google consent: fully automatic
- Fallback: tell user what happened and ask for the verification code
- NEVER ask the user to run
authcli refreshthemselves -- always use the expect script
Cross-Referencing from Other Skills
Any skill or workflow that runs cloud commands (BQ queries, bazel run with cloud targets,
gcloud commands, Roboflow submissions) should check for auth errors and invoke this skill.
To reference this skill from another SKILL.md, add to your pre-flight section:
## Pre-flight: Authentication
Before running cloud commands, check auth:
```bash
gcloud auth application-default print-access-token 2>&1 | head -1
If expired: Follow the cruise-auth-refresh skill (~/.cursor/skills/cruise-auth-refresh/SKILL.md).
This automates the full SSO flow. Only requires user interaction for Microsoft MFA number matching.
Skills that already reference this:
- `nvidia-featurization` (Section 0: Pre-flight Authentication)
- `trino-lakehouse` (Pre-flight: Authentication + Gotchas)
- `write-technical-report` (Pre-flight: Authentication)