Loading...
Loading...
Emulated Google OAuth 2.0 and OpenID Connect 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, 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", "local Google auth", or any task requiring a local Google OAuth/OIDC provider.
npx skill4agent add vercel-labs/emulate google# Google only
npx emulate --service google
# Default port
# http://localhost:4002import { createEmulator } from 'emulate'
const google = await createEmulator({ service: 'google', port: 4002 })
// google.url === 'http://localhost:4002'GOOGLE_EMULATOR_URL=http://localhost:4002| Real Google URL | Emulator URL |
|---|---|
| |
| |
| |
| |
| |
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',
})
// Override the endpoints
const authorizeUrl = client.generateAuthUrl({
access_type: 'offline',
scope: ['openid', 'email', 'profile'],
})
// Replace the host in authorizeUrl with GOOGLE_URL, or construct manually:
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=...`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`,
},
})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)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
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/googleclient_idclient_idclient_secretredirect_uricurl http://localhost:4002/.well-known/openid-configuration{
"issuer": "http://localhost:4002",
"authorization_endpoint": "http://localhost:4002/o/oauth2/v2/auth",
"token_endpoint": "http://localhost:4002/oauth2/token",
"userinfo_endpoint": "http://localhost:4002/oauth2/v2/userinfo",
"revocation_endpoint": "http://localhost:4002/oauth2/revoke",
"jwks_uri": "http://localhost:4002/oauth2/v3/certs",
"response_types_supported": ["code"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["HS256"],
"scopes_supported": ["openid", "email", "profile"],
"code_challenge_methods_supported": ["plain", "S256"]
}curl http://localhost:4002/oauth2/v3/certs{ "keys": [] }# 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"| Param | Description |
|---|---|
| OAuth client ID |
| Callback URL |
| Space-separated scopes ( |
| Opaque state for CSRF protection |
| Nonce for ID token (optional) |
| PKCE challenge (optional) |
| |
redirect_uri?code=...&state=...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"{
"access_token": "google_...",
"id_token": "<jwt>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid email profile"
}id_tokensubemailemail_verifiednamegiven_namefamily_namepicturelocalenoncecode_verifiercurl http://localhost:4002/oauth2/v2/userinfo \
-H "Authorization: Bearer google_..."{
"sub": "user-uid",
"email": "testuser@gmail.com",
"email_verified": true,
"name": "Test User",
"given_name": "Test",
"family_name": "User",
"picture": "https://lh3.googleusercontent.com/a/default-user",
"locale": "en"
}curl -X POST http://localhost:4002/oauth2/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=google_..."200 OKGOOGLE_URL="http://localhost:4002"
CLIENT_ID="my-client-id.apps.googleusercontent.com"
CLIENT_SECRET="GOCSPX-secret"
REDIRECT_URI="http://localhost:3000/api/auth/callback/google"
# 1. Open in browser -- user picks a seeded account
# $GOOGLE_URL/o/oauth2/v2/auth?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=openid+email+profile&response_type=code&state=abc
# 2. After user selection, emulator redirects to:
# $REDIRECT_URI?code=<code>&state=abc
# 3. Exchange code for tokens
curl -X POST $GOOGLE_URL/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=<code>&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI&grant_type=authorization_code"
# 4. Fetch user info with the access_token
curl $GOOGLE_URL/oauth2/v2/userinfo \
-H "Authorization: Bearer <access_token>"# Generate code_verifier and code_challenge
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-43)
CODE_CHALLENGE=$(echo -n $CODE_VERIFIER | openssl dgst -sha256 -binary | base64 | tr -d '=' | tr '+/' '-_')
# 1. Authorize with challenge
# $GOOGLE_URL/o/oauth2/v2/auth?...&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256
# 2. Token exchange with verifier
curl -X POST $GOOGLE_URL/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=<code>&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI&grant_type=authorization_code&code_verifier=$CODE_VERIFIER"openid-clientimport { Issuer } from 'openid-client'
const googleIssuer = await Issuer.discover(
process.env.GOOGLE_EMULATOR_URL ?? 'https://accounts.google.com'
)
const client = new googleIssuer.Client({
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirect_uris: ['http://localhost:3000/api/auth/callback/google'],
})