Google Cloud Platform & APIs
Systematic GCP deployment for Node.js applications with serverless architecture and Google API integration.
Overview
This Skill enforces:
- Cloud Run for serverless deployments
- Cloud Firestore for document storage
- Realtime Database for real-time data
- OAuth 2.0 authentication (user and service accounts)
- Service account management
- Google APIs integration
- Auto-scaling and cost optimization
- Security and access control
Apply when deploying to GCP, integrating Google services, or building serverless applications.
Google Cloud Setup
Create GCP Project
# Create project
gcloud projects create my-project --name="My Project"
# Set as active project
gcloud config set project my-project
# Enable services
gcloud services enable run.googleapis.com
gcloud services enable firestore.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
gcloud services enable cloudtasks.googleapis.com
Cloud Run Deployment
Deploy Node.js Application
# Build and deploy
gcloud run deploy my-app \
--source . \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars NODE_ENV=production
# Check deployment
gcloud run services list
gcloud run services describe my-app --region us-central1
Dockerfile for Cloud Run
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
app.js Configuration
import express from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send('Hello from Cloud Run!');
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Firestore Database
Initialize Firestore
// lib/firestore.ts
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.FIREBASE_APP_ID
};
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
CRUD Operations
import {
collection,
addDoc,
getDocs,
doc,
getDoc,
updateDoc,
deleteDoc,
query,
where
} from 'firebase/firestore';
// CREATE
async function createUser(userData: { email: string; name: string }) {
const docRef = await addDoc(collection(db, 'users'), {
email: userData.email,
name: userData.name,
createdAt: new Date()
});
return docRef.id;
}
// READ (single document)
async function getUser(userId: string) {
const docRef = doc(db, 'users', userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return docSnap.data();
} else {
throw new Error('User not found');
}
}
// READ (collection with query)
async function getUsersByEmail(email: string) {
const q = query(
collection(db, 'users'),
where('email', '==', email)
);
const querySnapshot = await getDocs(q);
const users: any[] = [];
querySnapshot.forEach(doc => {
users.push({ id: doc.id, ...doc.data() });
});
return users;
}
// UPDATE
async function updateUser(userId: string, updates: any) {
const userRef = doc(db, 'users', userId);
await updateDoc(userRef, {
...updates,
updatedAt: new Date()
});
}
// DELETE
async function deleteUser(userId: string) {
await deleteDoc(doc(db, 'users', userId));
}
Realtime Database
Firebase Realtime Setup
// lib/realtime-db.ts
import { initializeApp } from 'firebase/app';
import { getDatabase, ref, onValue, set, update, remove } from 'firebase/database';
const app = initializeApp(firebaseConfig);
export const realtimeDb = getDatabase(app);
// Real-time listener
function subscribeToPresence(userId: string, callback: (data: any) => void) {
const presenceRef = ref(realtimeDb, `presence/${userId}`);
const unsubscribe = onValue(presenceRef, snapshot => {
callback(snapshot.val());
});
return unsubscribe;
}
// Write data
async function setUserStatus(userId: string, status: string) {
const statusRef = ref(realtimeDb, `status/${userId}`);
await set(statusRef, {
status,
lastUpdated: new Date().toISOString()
});
}
Google OAuth 2.0 (User Authentication)
Setup OAuth Credentials
- Go to Google Cloud Console → APIs & Services → Credentials
- Create OAuth 2.0 Client ID
- Set authorized redirect URIs
OAuth Implementation
// lib/google-oauth.ts
import { google } from 'googleapis';
import session from 'express-session';
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URL
);
// Route: Start OAuth flow
app.get('/auth/google', (req, res) => {
const scopes = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'
];
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
res.redirect(authUrl);
});
// Route: OAuth callback
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
try {
const { tokens } = await oauth2Client.getToken(code as string);
oauth2Client.setCredentials(tokens);
// Use tokens to get user info
const oauth2 = google.oauth2({
auth: oauth2Client,
version: 'v2'
});
const userinfo = await oauth2.userinfo.get();
req.session.user = userinfo.data;
req.session.tokens = tokens;
res.redirect('/dashboard');
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
});
// Middleware: Check authentication
export function requireAuth(req: any, res: any, next: any) {
if (!req.session.user) {
return res.redirect('/auth/google');
}
next();
}
Google Service Accounts (Server-to-Server)
Create Service Account
# Create service account
gcloud iam service-accounts create my-service-account \
--display-name="My Service Account"
# Create key file
gcloud iam service-accounts keys create key.json \
--iam-account=my-service-account@my-project.iam.gserviceaccount.com
# Grant permissions
gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:my-service-account@my-project.iam.gserviceaccount.com" \
--role="roles/editor"
Use Service Account
// lib/service-account.ts
import { google } from 'googleapis';
const serviceAccount = require('./key.json');
const auth = new google.auth.GoogleAuth({
keyFile: './key.json',
scopes: [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/calendar'
]
});
const drive = google.drive({ version: 'v3', auth });
const calendar = google.calendar({ version: 'v3', auth });
// Example: List Google Drive files
export async function listDriveFiles() {
const res = await drive.files.list({
pageSize: 10,
fields: 'files(id, name)'
});
return res.data.files;
}
// Example: Create calendar event
export async function createCalendarEvent(calendarId: string, event: any) {
const res = await calendar.events.insert({
calendarId,
requestBody: {
summary: event.title,
description: event.description,
start: { dateTime: event.startTime },
end: { dateTime: event.endTime }
}
});
return res.data;
}
Google APIs Examples
Gmail API
// Send email
export async function sendEmail(to: string, subject: string, body: string) {
const message = [
`To: ${to}`,
`Subject: ${subject}`,
'',
body
].join('\n');
const encodedMessage = Buffer.from(message)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_');
const res = await gmail.users.messages.send({
userId: 'me',
requestBody: {
raw: encodedMessage
}
});
return res.data;
}
Sheets API
// Write to Google Sheet
export async function writeToSheet(spreadsheetId: string, values: any[]) {
const res = await sheets.spreadsheets.values.append({
spreadsheetId,
range: 'Sheet1!A1',
valueInputOption: 'RAW',
requestBody: { values }
});
return res.data;
}
// Read from Google Sheet
export async function readFromSheet(spreadsheetId: string) {
const res = await sheets.spreadsheets.values.get({
spreadsheetId,
range: 'Sheet1'
});
return res.data.values;
}
Environment Variables
.env Configuration
# Google Cloud
GCP_PROJECT_ID=my-project
GCP_REGION=us-central1
# Firebase
FIREBASE_API_KEY=xxx
FIREBASE_AUTH_DOMAIN=xxx.firebaseapp.com
FIREBASE_PROJECT_ID=my-project
FIREBASE_STORAGE_BUCKET=xxx.appspot.com
FIREBASE_MESSAGING_SENDER_ID=xxx
FIREBASE_APP_ID=xxx
# OAuth
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxx
GOOGLE_REDIRECT_URL=http://localhost:3000/auth/callback
# Service Account
GOOGLE_APPLICATION_CREDENTIALS=./key.json
Deployment with CI/CD
GitHub Actions Workflow
# .github/workflows/deploy.yml
name: Deploy to Cloud Run
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}
- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v1
with:
service: my-app
region: us-central1
image: gcr.io/${{ secrets.GCP_PROJECT_ID }}/my-app
env_vars: |
NODE_ENV=production
FIREBASE_PROJECT_ID=${{ secrets.GCP_PROJECT_ID }}
Anti-Patterns
// ❌ BAD: Hardcoded credentials
const oauth2Client = new google.auth.OAuth2(
'hardcoded-client-id',
'hardcoded-secret',
'http://localhost:3000/callback'
);
// ✅ GOOD: Use environment variables
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URL
);
// ❌ BAD: No error handling
const tokens = await oauth2Client.getToken(code);
// Crashes if getToken fails
// ✅ GOOD: Error handling
try {
const { tokens } = await oauth2Client.getToken(code);
oauth2Client.setCredentials(tokens);
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
// ❌ BAD: Querying all documents
const allUsers = await getDocs(collection(db, 'users'));
// ✅ GOOD: Filter with where clause
const q = query(collection(db, 'users'), where('active', '==', true));
const activeUsers = await getDocs(q);
Verification Before Production
- Service account created with appropriate permissions
- OAuth credentials configured with redirect URIs
- Firestore indexes created for queries
- Environment variables configured
- HTTPS enabled for OAuth callback
- Error handling for API calls
- Rate limiting configured
- Cloud Run health checks configured
- CI/CD pipeline set up
- Secrets managed securely (not in code)
Integration with Project Standards
Enforces security and deployment best practices:
- S-5: Secrets in environment variables
- No hardcoded credentials
- Service account least-privilege access
- OAuth2 standard compliance
Resources
- Google Cloud Run: https://cloud.google.com/run/docs
- Firebase: https://firebase.google.com/docs
- Google APIs: https://developers.google.com/apis-explorer
- OAuth 2.0: https://developers.google.com/identity/protocols/oauth2
Last Updated: January 24, 2026 Compatibility: Claude Opus 4.5, Claude Code v2.x Status: Production Ready
January 2026 Update: This skill is compatible with Claude Opus 4.5 and Claude Code v2.x. For complex tasks, use the
effort: highparameter for thorough analysis.