Skip to main content

google

Emulated Google OAuth 2.0, OpenID Connect, Gmail, Calendar, and Drive for local development and testing. Use when the user needs to test Google sign-in locally, emulate OIDC discovery, handle Google token exchange, configure Google OAuth clients, work with Gmail messages/drafts/threads/labels, manage Calendar events, upload or list Drive files, or work with Google userinfo without hitting real Google APIs. Triggers include "Google OAuth", "emulate Google", "mock Google login", "test Google sign-in", "OIDC emulator", "Google OIDC", "Gmail API", "Google Calendar", "Google Drive", "local Google auth", or any task requiring a local Google API.

Source facts

Repository
vercel-labs/emulate
Last source activity
October 14, 2026 at 17:08
Detected SKILL.md language
English
Stars
1,893
Forks
138

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
google
description
Emulated Google OAuth 2.0, OpenID Connect, Gmail, Calendar, and Drive for local development and testing. Use when the user needs to test Google sign-in locally, emulate OIDC discovery, handle Google token exchange, configure Google OAuth clients, work with Gmail messages/drafts/threads/labels, manage Calendar events, upload or list Drive files, or work with Google userinfo without hitting real Google APIs. Triggers include "Google OAuth", "emulate Google", "mock Google login", "test Google sign-in", "OIDC emulator", "Google OIDC", "Gmail API", "Google Calendar", "Google Drive", "local Google auth", or any task requiring a local Google API.
allowed-tools
Bash(npx emulate:*), Bash(curl:*)
# Google OAuth 2.0 / OIDC + Gmail, Calendar & Drive Emulator OAuth 2.0 and OpenID Connect emulation with authorization code flow, PKCE support, ID tokens, OIDC discovery, refresh tokens, plus Gmail, Google Calendar, and Google Drive REST API surfaces. ## Start Local listeners bind to `127.0.0.1` by default. For access from containers or other machines, pass `--host 0.0.0.0` to the CLI or `hostname: '0.0.0.0'` to `createEmulator`. Configure `--base-url` or `baseUrl` for advertised URLs reachable by those clients. ```bash # Google only npx emulate --service google # Default port # http://localhost:4002 ``` Or programmatically: ```typescript import { createEmulator } from 'emulate' const google = await createEmulator({ service: 'google', port: 4002 }) // google.url === 'http://localhost:4002' ``` ## Pointing Your App at the Emulator ### Environment Variable ```bash GOOGLE_EMULATOR_URL=http://localhost:4002 ``` ### OAuth URL Mapping | Real Google URL | Emulator URL | |-----------------|-------------| | `https://accounts.google.com/o/oauth2/v2/auth` | `$GOOGLE_EMULATOR_URL/o/oauth2/v2/auth` | | `https://oauth2.googleapis.com/token` | `$GOOGLE_EMULATOR_URL/oauth2/token` | | `https://www.googleapis.com/oauth2/v2/userinfo` | `$GOOGLE_EMULATOR_URL/oauth2/v2/userinfo` | | `https://accounts.google.com/.well-known/openid-configuration` | `$GOOGLE_EMULATOR_URL/.well-known/openid-configuration` | | `https://www.googleapis.com/oauth2/v3/certs` | `$GOOGLE_EMULATOR_URL/oauth2/v3/certs` | | `https://gmail.googleapis.com/gmail/v1/...` | `$GOOGLE_EMULATOR_URL/gmail/v1/...` | | `https://www.googleapis.com/calendar/v3/...` | `$GOOGLE_EMULATOR_URL/calendar/v3/...` | | `https://www.googleapis.com/drive/v3/...` | `$GOOGLE_EMULATOR_URL/drive/v3/...` | ### google-auth-library (Node.js) ```typescript import { OAuth2Client } from 'google-auth-library' const GOOGLE_URL = process.env.GOOGLE_EMULATOR_URL ?? 'https://accounts.google.com' const client = new OAuth2Client({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, redirectUri: 'http://localhost:3000/api/auth/callback/google', }) const emulatorAuthorizeUrl = `${GOOGLE_URL}/o/oauth2/v2/auth?client_id=${process.env.GOOGLE_CLIENT_ID}&redirect_uri=...&scope=openid+email+profile&response_type=code&state=...` ``` ### Auth.js / NextAuth.js ```typescript import Google from '@auth/core/providers/google' Google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorization: { url: `${process.env.GOOGLE_EMULATOR_URL}/o/oauth2/v2/auth`, params: { scope: 'openid email profile' }, }, token: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/token`, }, userinfo: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/v2/userinfo`, }, }) ``` ### Passport.js ```typescript import { Strategy as GoogleStrategy } from 'passport-google-oauth20' const GOOGLE_URL = process.env.GOOGLE_EMULATOR_URL ?? 'https://accounts.google.com' new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: 'http://localhost:3000/api/auth/callback/google', authorizationURL: `${GOOGLE_URL}/o/oauth2/v2/auth`, tokenURL: `${GOOGLE_URL}/oauth2/token`, userProfileURL: `${GOOGLE_URL}/oauth2/v2/userinfo`, }, verifyCallback) ``` ## Seed Config ```yaml google: users: - email: testuser@gmail.com name: Test User given_name: Test family_name: User picture: https://lh3.googleusercontent.com/a/default-user email_verified: true locale: en - email: dev@example.com name: Developer - email: admin@acme.com name: Admin hd: acme.com oauth_clients: - client_id: my-client-id.apps.googleusercontent.com client_secret: GOCSPX-secret name: My App redirect_uris: - http://localhost:3000/api/auth/callback/google labels: - id: Label_ops user_email: testuser@gmail.com name: Ops/Review color_background: "#DDEEFF" color_text: "#111111" messages: - id: msg_welcome user_email: testuser@gmail.com thread_id: thr_welcome from: "welcome@example.com" to: testuser@gmail.com subject: Welcome to the Gmail emulator body_text: You can now test Gmail flows locally. label_ids: [INBOX, UNREAD, CATEGORY_UPDATES] date: "2025-01-04T10:00:00.000Z" calendars: - id: primary user_email: testuser@gmail.com summary: testuser@gmail.com primary: true selected: true time_zone: UTC calendar_events: - id: evt_kickoff user_email: testuser@gmail.com calendar_id: primary summary: Project Kickoff start_date_time: "2025-01-10T09:00:00.000Z" end_date_time: "2025-01-10T09:30:00.000Z" attendees: - email: testuser@gmail.com display_name: Test User conference_entry_points: - entry_point_type: video uri: https://meet.google.com/example label: Google Meet hangout_link: https://meet.google.com/example drive_items: - id: drv_docs user_email: testuser@gmail.com name: Docs mime_type: application/vnd.google-apps.folder parent_ids: [root] - id: drv_readme user_email: testuser@gmail.com name: README.md mime_type: text/markdown parent_ids: [drv_docs] data: "# Hello World" ``` When no OAuth clients are configured, the emulator accepts any `client_id`. With clients configured, strict validation is enforced for `client_id`, `client_secret`, and `redirect_uri`. Google authentication is permissive by default for local bearer-token workflows. Set `google.strict_scopes: true` in seed config to require emulator-issued, unexpired access tokens on Gmail, Calendar, Drive, and userinfo routes. Invalid credentials return `401 UNAUTHENTICATED`; missing method scopes return `403` with `insufficientPermissions`. Strict mode distinguishes read, write, send, settings, and metadata scopes, and userinfo includes only granted identity claims. Revoking an access or refresh token invalidates the linked access and refresh credentials. Discovery, signing keys, and the sign-in page remain public. This mode checks method scopes; resource-specific grants such as `drive.file` and Gmail add-on scopes are not modeled. ### Hosted domain (hd) claim Google Workspace accounts include an `hd` claim in ID tokens and userinfo responses identifying the user's hosted domain. The emulator derives this automatically from the user's email domain. Consumer domains (`gmail.com`, `googlemail.com`) omit the claim, matching real Google behavior. To override the derived value, set `hd` on a seeded user. To suppress the claim entirely, set `hd` to an empty string. ## OAuth / OIDC Endpoints ### OIDC Discovery ```bash curl http://localhost:4002/.well-known/openid-configuration ``` ### JWKS ```bash curl http://localhost:4002/oauth2/v3/certs ``` Returns the RSA public key used to verify the ID tokens issued by the emulator. Google ID tokens use RS256, and the discovery document advertises the same algorithm. ### Authorization ```bash # Browser flow: redirects to a user picker page curl -v "http://localhost:4002/o/oauth2/v2/auth?\ client_id=my-client-id.apps.googleusercontent.com&\ redirect_uri=http://localhost:3000/api/auth/callback/google&\ scope=openid+email+profile&\ response_type=code&\ state=random-state&\ nonce=random-nonce" ``` Supports `code_challenge` and `code_challenge_method` for PKCE. ### Token Exchange ```bash curl -X POST http://localhost:4002/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "code=<authorization_code>&\ client_id=my-client-id.apps.googleusercontent.com&\ client_secret=GOCSPX-secret&\ redirect_uri=http://localhost:3000/api/auth/callback/google&\ grant_type=authorization_code" ``` Also accepts `application/json` body. Returns: ```json { "access_token": "google_...", "refresh_token": "google_refresh_...", "id_token": "<jwt>", "token_type": "Bearer", "expires_in": 3600, "scope": "openid email profile" } ``` ### Refresh Token ```bash curl -X POST http://localhost:4002/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "refresh_token=google_refresh_...&\ client_id=my-client-id.apps.googleusercontent.com&\ client_secret=GOCSPX-secret&\ grant_type=refresh_token" ``` Returns a new `access_token` (no new `refresh_token` or `id_token` on refresh). ### User Info ```bash curl http://localhost:4002/oauth2/v2/userinfo \ -H "Authorization: Bearer google_..." ``` ### Token Revocation ```bash curl -X POST http://localhost:4002/oauth2/revoke \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "token=google_..." ``` ## Gmail API All Gmail endpoints are under `/gmail/v1/users/:userId/...` where `:userId` is `me` or the authenticated user's email. ### Messages ```bash # List messages (filter by labels, search query) curl "http://localhost:4002/gmail/v1/users/me/messages?labelIds=INBOX&q=from:welcome&maxResults=10" \ -H "Authorization: Bearer $TOKEN" # Get message (format: full, metadata, minimal, raw) curl "http://localhost:4002/gmail/v1/users/me/messages/msg_welcome?format=full" \ -H "Authorization: Bearer $TOKEN" # Send message curl -X POST http://localhost:4002/gmail/v1/users/me/messages/send \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"to": "someone@example.com", "subject": "Hello", "body_text": "Hi there"}' # Insert message (bypass send) curl -X POST http://localhost:4002/gmail/v1/users/me/messages \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"to": "test@example.com", "from": "me@example.com", "subject": "Test", "body_text": "Body", "labelIds": ["INBOX"]}' # Import message curl -X POST http://localhost:4002/gmail/v1/users/me/messages/import \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"to": "test@example.com", "from": "external@example.com", "subject": "Imported", "body_text": "Content"}' # Modify labels on a message curl -X POST http://localhost:4002/gmail/v1/users/me/messages/msg_welcome/modify \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"addLabelIds": ["STARRED"], "removeLabelIds": ["UNREAD"]}' # Trash / untrash curl -X POST http://localhost:4002/gmail/v1/users/me/messages/msg_welcome/trash \ -H "Authorization: Bearer $TOKEN" curl -X POST http://localhost:4002/gmail/v1/users/me/messages/msg_welcome/untrash \ -H "Authorization: Bearer $TOKEN" # Delete permanently
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub