@ssheleg/sheleg-dev 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +172 -0
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/SECURITY.md +63 -0
- package/bin/sheleg-dev.js +99 -0
- package/package.json +45 -0
- package/plugins/sheleg-dev/.claude-plugin/plugin.json +28 -0
- package/plugins/sheleg-dev/skills/ad-tracking/SKILL.md +442 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/consent-mode.md +257 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/event-tracking.md +201 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/gtag-api.md +389 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/meta-linkedin.md +103 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/performance-security.md +288 -0
- package/plugins/sheleg-dev/skills/crypto-payments/SKILL.md +384 -0
- package/plugins/sheleg-dev/skills/crypto-payments/references/heleket-provider.md +1357 -0
- package/plugins/sheleg-dev/skills/frontend-performance/SKILL.md +147 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/accessibility-perf.md +172 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/css-performance.md +180 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/nextjs.md +271 -0
- package/plugins/sheleg-dev/skills/google-auth/SKILL.md +275 -0
- package/plugins/sheleg-dev/skills/google-auth/references/adc-and-service-accounts.md +464 -0
- package/plugins/sheleg-dev/skills/google-auth/references/oauth2-web-server.md +615 -0
- package/plugins/sheleg-dev/skills/google-auth/references/sign-in-with-google.md +593 -0
- package/plugins/sheleg-dev/skills/google-auth/references/workload-identity.md +376 -0
- package/plugins/sheleg-dev/skills/google-signin/SKILL.md +121 -0
- package/plugins/sheleg-dev/skills/google-signin/references/full-guide.md +421 -0
- package/plugins/sheleg-dev/skills/stripe-billing/SKILL.md +458 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/price-integrity.md +201 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/stripe-agent-toolchain.md +173 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/subscription-lifecycle.md +294 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/testing-and-local-dev.md +214 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/webhook-events.md +211 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Next.js Performance Patterns
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Contents
|
|
5
|
+
|
|
6
|
+
- [Font Optimization with `next/font`](#font-optimization-with-nextfont)
|
|
7
|
+
- [Code Splitting with `next/dynamic`](#code-splitting-with-nextdynamic)
|
|
8
|
+
- [Cache Headers in `next.config.ts`](#cache-headers-in-nextconfigts)
|
|
9
|
+
- [Content Security Policy](#content-security-policy)
|
|
10
|
+
- [Script Loading Strategy](#script-loading-strategy)
|
|
11
|
+
- [Image Optimization](#image-optimization)
|
|
12
|
+
- [Bundle Analysis](#bundle-analysis)
|
|
13
|
+
- [Browserslist Configuration](#browserslist-configuration)
|
|
14
|
+
|
|
15
|
+
## Font Optimization with `next/font`
|
|
16
|
+
|
|
17
|
+
### Migration from `<link>` to `next/font/google`
|
|
18
|
+
|
|
19
|
+
Replace external Google Fonts links with `next/font/google` imports. This:
|
|
20
|
+
- Inlines font CSS at build time (no render-blocking request)
|
|
21
|
+
- Self-hosts font files from `/_next/static/` (no external dependency)
|
|
22
|
+
- Eliminates need for `preconnect` hints and Google Fonts CSP entries
|
|
23
|
+
- Enables automatic subsetting
|
|
24
|
+
|
|
25
|
+
**Before (bad):**
|
|
26
|
+
```tsx
|
|
27
|
+
// layout.tsx
|
|
28
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
29
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
30
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Sans&family=Outfit&display=swap" rel="stylesheet" />
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**After (good):**
|
|
34
|
+
```tsx
|
|
35
|
+
// layout.tsx
|
|
36
|
+
import { DM_Sans, Outfit } from "next/font/google";
|
|
37
|
+
|
|
38
|
+
const dmSans = DM_Sans({
|
|
39
|
+
subsets: ["latin"],
|
|
40
|
+
variable: "--font-dm-sans",
|
|
41
|
+
weight: ["400", "500", "600", "700"],
|
|
42
|
+
display: "swap",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const outfit = Outfit({
|
|
46
|
+
subsets: ["latin"],
|
|
47
|
+
variable: "--font-outfit",
|
|
48
|
+
weight: ["400", "500", "600", "700", "800"],
|
|
49
|
+
display: "swap",
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export default function RootLayout({ children }) {
|
|
53
|
+
return (
|
|
54
|
+
<html lang="en" className={`${dmSans.variable} ${outfit.variable}`}>
|
|
55
|
+
<body>{children}</body>
|
|
56
|
+
</html>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then reference via CSS variables in `globals.css`:
|
|
62
|
+
```css
|
|
63
|
+
body { font-family: var(--font-dm-sans), system-ui, sans-serif; }
|
|
64
|
+
h1, h2, h3 { font-family: var(--font-outfit), system-ui, sans-serif; }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Multiple Font Families
|
|
68
|
+
|
|
69
|
+
Load only fonts actually used. Each family adds ~20-50KB. Three families is a practical maximum for landing pages.
|
|
70
|
+
|
|
71
|
+
If using variable fonts (weight ranges), specify the range:
|
|
72
|
+
```tsx
|
|
73
|
+
const dmSans = DM_Sans({
|
|
74
|
+
subsets: ["latin"],
|
|
75
|
+
variable: "--font-dm-sans",
|
|
76
|
+
weight: ["400", "500", "600", "700"], // or omit for variable font full range
|
|
77
|
+
display: "swap",
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Code Splitting with `next/dynamic`
|
|
82
|
+
|
|
83
|
+
Lazy-load below-the-fold sections to reduce initial JavaScript bundle:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import dynamic from "next/dynamic";
|
|
87
|
+
|
|
88
|
+
// Above-the-fold: import normally
|
|
89
|
+
import { HeroSection } from "@/components/hero";
|
|
90
|
+
import { Navbar } from "@/components/navbar";
|
|
91
|
+
|
|
92
|
+
// Below-the-fold: lazy load
|
|
93
|
+
const Testimonials = dynamic(() =>
|
|
94
|
+
import("@/components/testimonials").then((m) => m.TestimonialsSection)
|
|
95
|
+
);
|
|
96
|
+
const FAQ = dynamic(() =>
|
|
97
|
+
import("@/components/faq").then((m) => m.FAQSection)
|
|
98
|
+
);
|
|
99
|
+
const Pricing = dynamic(() =>
|
|
100
|
+
import("@/components/pricing").then((m) => m.PricingSection)
|
|
101
|
+
);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Only use `next/dynamic` for components that are:
|
|
105
|
+
- Below the initial viewport (not visible without scrolling)
|
|
106
|
+
- Heavy (> 10KB compressed)
|
|
107
|
+
- Not critical for SEO (search engines execute JS but slower)
|
|
108
|
+
|
|
109
|
+
Do NOT dynamically import the hero, navbar, or footer -- these must render immediately.
|
|
110
|
+
|
|
111
|
+
## Cache Headers in `next.config.ts`
|
|
112
|
+
|
|
113
|
+
Add cache headers for static assets:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// next.config.ts
|
|
117
|
+
const nextConfig = {
|
|
118
|
+
async headers() {
|
|
119
|
+
return [
|
|
120
|
+
{
|
|
121
|
+
source: "/:path*.:ext(svg|png|jpg|jpeg|gif|webp|ico|woff|woff2)",
|
|
122
|
+
headers: [
|
|
123
|
+
{
|
|
124
|
+
key: "Cache-Control",
|
|
125
|
+
value: "public, max-age=31536000, immutable",
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Critical:** Next.js uses `path-to-regexp` for route matching. Common pattern mistakes:
|
|
135
|
+
|
|
136
|
+
| Pattern | Works? | Why |
|
|
137
|
+
|---------|--------|-----|
|
|
138
|
+
| `/:path*{.svg,.png}` | No | Braces are literal in path-to-regexp |
|
|
139
|
+
| `/:path*.(svg\|png)` | No | Pipe needs to be inside a named param |
|
|
140
|
+
| `/:path*.:ext(svg\|png\|jpg)` | Yes | Regex parameter syntax |
|
|
141
|
+
|
|
142
|
+
Test patterns before deploying:
|
|
143
|
+
```javascript
|
|
144
|
+
const { match } = require("path-to-regexp");
|
|
145
|
+
const fn = match("/:path*.:ext(svg|png|jpg)");
|
|
146
|
+
console.log(fn("/logo.svg")); // { params: { path: ["logo"], ext: "svg" } }
|
|
147
|
+
console.log(fn("/page")); // false
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Content Security Policy
|
|
151
|
+
|
|
152
|
+
Configure CSP in `next.config.ts` security headers:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
{
|
|
156
|
+
source: "/(.*)",
|
|
157
|
+
headers: [
|
|
158
|
+
{
|
|
159
|
+
key: "Content-Security-Policy",
|
|
160
|
+
value: [
|
|
161
|
+
"default-src 'self'",
|
|
162
|
+
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com https://www.google-analytics.com https://static.cloudflareinsights.com",
|
|
163
|
+
"style-src 'self' 'unsafe-inline'",
|
|
164
|
+
"img-src 'self' data: blob: https:",
|
|
165
|
+
"font-src 'self'",
|
|
166
|
+
"connect-src 'self' https://www.google-analytics.com https://vitals.vercel-insights.com",
|
|
167
|
+
].join("; "),
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Rules:**
|
|
174
|
+
- After migrating fonts to `next/font`, remove `fonts.googleapis.com` from `style-src` and `fonts.gstatic.com` from `font-src` -- self-hosted fonts are covered by `'self'`.
|
|
175
|
+
- Every new third-party script/style requires a CSP update.
|
|
176
|
+
- CSP violations show as console errors and directly lower the Best Practices score.
|
|
177
|
+
|
|
178
|
+
## Script Loading Strategy
|
|
179
|
+
|
|
180
|
+
Use `next/script` for third-party scripts:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import Script from "next/script";
|
|
184
|
+
|
|
185
|
+
// Google Analytics -- load after page is interactive
|
|
186
|
+
<Script
|
|
187
|
+
src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`}
|
|
188
|
+
strategy="afterInteractive"
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
| Strategy | When | Use For |
|
|
193
|
+
|----------|------|---------|
|
|
194
|
+
| `beforeInteractive` | Before hydration | Critical polyfills, A/B test scripts |
|
|
195
|
+
| `afterInteractive` | After hydration (default) | Analytics, tracking |
|
|
196
|
+
| `lazyOnload` | After everything | Chat widgets, social embeds |
|
|
197
|
+
| `worker` | In web worker (experimental) | Heavy non-critical scripts |
|
|
198
|
+
|
|
199
|
+
Never use raw `<script>` tags in Next.js -- they bypass optimization.
|
|
200
|
+
|
|
201
|
+
## Image Optimization
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import Image from "next/image";
|
|
205
|
+
|
|
206
|
+
// LCP hero image -- priority load
|
|
207
|
+
<Image
|
|
208
|
+
src="/hero.webp"
|
|
209
|
+
alt="Product dashboard showing analytics"
|
|
210
|
+
width={1200}
|
|
211
|
+
height={630}
|
|
212
|
+
priority
|
|
213
|
+
sizes="100vw"
|
|
214
|
+
/>
|
|
215
|
+
|
|
216
|
+
// Below-fold image -- lazy load (default)
|
|
217
|
+
<Image
|
|
218
|
+
src="/feature.webp"
|
|
219
|
+
alt="Feature screenshot"
|
|
220
|
+
width={600}
|
|
221
|
+
height={400}
|
|
222
|
+
sizes="(max-width: 768px) 100vw, 50vw"
|
|
223
|
+
/>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Rules:**
|
|
227
|
+
- Always set `priority` on the LCP image (usually the hero).
|
|
228
|
+
- Always provide `sizes` for responsive images.
|
|
229
|
+
- Always provide `width` and `height` to prevent CLS.
|
|
230
|
+
- Use `alt=""` for decorative images (logos next to brand text).
|
|
231
|
+
- Remote images require `remotePatterns` in `next.config.ts`.
|
|
232
|
+
|
|
233
|
+
## Bundle Analysis
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Install analyzer
|
|
237
|
+
npm install -D @next/bundle-analyzer
|
|
238
|
+
|
|
239
|
+
# Add to next.config.ts
|
|
240
|
+
const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
|
241
|
+
enabled: process.env.ANALYZE === "true",
|
|
242
|
+
});
|
|
243
|
+
module.exports = withBundleAnalyzer(nextConfig);
|
|
244
|
+
|
|
245
|
+
# Run analysis
|
|
246
|
+
ANALYZE=true next build
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Look for:
|
|
250
|
+
- Large dependencies (lodash, moment.js) that can be replaced
|
|
251
|
+
- Duplicate packages across chunks
|
|
252
|
+
- Server-only code leaking into client bundles
|
|
253
|
+
|
|
254
|
+
## Browserslist Configuration
|
|
255
|
+
|
|
256
|
+
Add to `package.json` to reduce polyfill shipping:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"browserslist": [
|
|
261
|
+
"last 2 Chrome versions",
|
|
262
|
+
"last 2 Firefox versions",
|
|
263
|
+
"last 2 Safari versions",
|
|
264
|
+
"last 2 Edge versions"
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
This tells SWC to skip polyfills for `Array.prototype.at`, `Object.fromEntries`, `String.prototype.trimStart`, etc. Saves ~10-15KB on typical bundles.
|
|
270
|
+
|
|
271
|
+
Note: Some polyfills are bundled by Next.js core and cannot be eliminated via `browserslist`.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: google-auth
|
|
3
|
+
description: >-
|
|
4
|
+
Use when implementing Google authentication in a Node.js or Python web application — Google
|
|
5
|
+
login, OAuth 2.0 flows, verifying Google ID tokens, service account authentication,
|
|
6
|
+
Application Default Credentials, Google Identity Services, Workload Identity Federation, API
|
|
7
|
+
keys, or working with google-auth-library (Node.js) or google-auth (Python). Covers ID token
|
|
8
|
+
verification and security best practices. Triggers - "google auth", "google login", "google
|
|
9
|
+
sign in", "OAuth 2.0 Google", "google-auth-library", "Sign In with Google", "Google Identity
|
|
10
|
+
Services", "GIS", "ADC", "Application Default Credentials", "service account", "Google ID
|
|
11
|
+
token", "verifyIdToken", "GOOGLE_APPLICATION_CREDENTIALS", "Google SSO", "вход через Google",
|
|
12
|
+
"авторизация Google", "сервисный аккаунт", "проверить ID-токен", "гугл-логин". For end-user
|
|
13
|
+
web sign-in only, use the google-signin skill instead.
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Google Authentication for Node.js & Python
|
|
17
|
+
|
|
18
|
+
## Libraries
|
|
19
|
+
|
|
20
|
+
### Node.js
|
|
21
|
+
|
|
22
|
+
- `google-auth-library` — core auth library (OAuth2Client, GoogleAuth, JWT, Compute, Impersonated)
|
|
23
|
+
- `googleapis` — Google API client (wraps google-auth-library)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install google-auth-library
|
|
27
|
+
npm install googleapis
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Python
|
|
31
|
+
|
|
32
|
+
- `google-auth` — core auth library (google.oauth2, google.auth, credentials, transport)
|
|
33
|
+
- `google-auth-oauthlib` — OAuth 2.0 user-credential flow helpers (Flow, InstalledAppFlow)
|
|
34
|
+
- `google-api-python-client` — Google API client (wraps google-auth)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install google-auth
|
|
38
|
+
pip install google-auth-oauthlib
|
|
39
|
+
pip install google-api-python-client
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Authentication Methods Overview
|
|
43
|
+
|
|
44
|
+
| Method | Use Case | Node.js Key Class | Python Key Module / Class |
|
|
45
|
+
|--------|----------|-------------------|---------------------------|
|
|
46
|
+
| **ADC** | Same identity for all users, server-to-server | `GoogleAuth` | `google.auth.default()` |
|
|
47
|
+
| **OAuth 2.0** | Actions on behalf of end users | `OAuth2Client` | `google_auth_oauthlib.flow.Flow` |
|
|
48
|
+
| **Sign In with Google (GIS)** | User sign-in/sign-up on websites | GIS JS SDK + `verifyIdToken()` | GIS JS SDK + `id_token.verify_oauth2_token()` |
|
|
49
|
+
| **JWT / Service Account** | Server-to-server, single identity | `JWT` | `service_account.Credentials` |
|
|
50
|
+
| **API Key** | Public data, no user context | `OAuth2Client({ apiKey })` | passed to `googleapiclient.discovery.build(developerKey=)` |
|
|
51
|
+
| **Compute** | On GCP with attached service account | `Compute` | `google.auth.compute_engine.Credentials` |
|
|
52
|
+
| **Workload Identity Federation** | AWS/Azure/OIDC → GCP without SA keys | `ExternalAccountClient` | `google.auth.identity_pool.Credentials` / `google.auth.aws.Credentials` |
|
|
53
|
+
|
|
54
|
+
## Quick Patterns
|
|
55
|
+
|
|
56
|
+
### 1. Application Default Credentials (ADC)
|
|
57
|
+
|
|
58
|
+
**Node.js**
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
const {GoogleAuth} = require('google-auth-library');
|
|
62
|
+
|
|
63
|
+
const auth = new GoogleAuth({
|
|
64
|
+
scopes: 'https://www.googleapis.com/auth/cloud-platform'
|
|
65
|
+
});
|
|
66
|
+
const client = await auth.getClient();
|
|
67
|
+
const res = await client.fetch('https://dns.googleapis.com/dns/v1/projects/...');
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Python**
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import google.auth
|
|
74
|
+
import google.auth.transport.requests
|
|
75
|
+
|
|
76
|
+
credentials, project = google.auth.default(
|
|
77
|
+
scopes=['https://www.googleapis.com/auth/cloud-platform']
|
|
78
|
+
)
|
|
79
|
+
request = google.auth.transport.requests.Request()
|
|
80
|
+
credentials.refresh(request)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
ADC search order: attached service account → `gcloud auth application-default login` file → `GOOGLE_APPLICATION_CREDENTIALS` env var.
|
|
84
|
+
|
|
85
|
+
For detailed ADC setup and service account usage, see [references/adc-and-service-accounts.md](references/adc-and-service-accounts.md).
|
|
86
|
+
|
|
87
|
+
### 2. OAuth 2.0 Web Server Flow
|
|
88
|
+
|
|
89
|
+
**Node.js**
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
const {OAuth2Client} = require('google-auth-library');
|
|
93
|
+
|
|
94
|
+
const client = new OAuth2Client({
|
|
95
|
+
clientId: CLIENT_ID,
|
|
96
|
+
clientSecret: CLIENT_SECRET,
|
|
97
|
+
redirectUri: REDIRECT_URI
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const authUrl = client.generateAuthUrl({
|
|
101
|
+
access_type: 'offline',
|
|
102
|
+
scope: ['https://www.googleapis.com/auth/userinfo.profile'],
|
|
103
|
+
state: crypto.randomBytes(32).toString('hex'),
|
|
104
|
+
include_granted_scopes: true
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// After redirect: exchange code for tokens
|
|
108
|
+
const {tokens} = await client.getToken(code);
|
|
109
|
+
client.setCredentials(tokens);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Python**
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from google_auth_oauthlib.flow import Flow
|
|
116
|
+
|
|
117
|
+
flow = Flow.from_client_secrets_file(
|
|
118
|
+
'client_secret.json',
|
|
119
|
+
scopes=['https://www.googleapis.com/auth/userinfo.profile'],
|
|
120
|
+
redirect_uri=REDIRECT_URI
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
authorization_url, state = flow.authorization_url(
|
|
124
|
+
access_type='offline',
|
|
125
|
+
include_granted_scopes='true'
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# After redirect: exchange code for tokens
|
|
129
|
+
flow.fetch_token(code=code)
|
|
130
|
+
credentials = flow.credentials
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`refresh_token` is only returned on the first authorization. Use `prompt: 'consent'` (Node.js) or `prompt='consent'` (Python) to force re-consent.
|
|
134
|
+
|
|
135
|
+
For the complete OAuth 2.0 flow (parameters, token exchange, refresh, revocation, incremental auth), see [references/oauth2-web-server.md](references/oauth2-web-server.md).
|
|
136
|
+
|
|
137
|
+
### 3. Sign In with Google — ID Token Verification
|
|
138
|
+
|
|
139
|
+
**Node.js**
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
const {OAuth2Client} = require('google-auth-library');
|
|
143
|
+
const client = new OAuth2Client();
|
|
144
|
+
|
|
145
|
+
const ticket = await client.verifyIdToken({
|
|
146
|
+
idToken: token,
|
|
147
|
+
audience: WEB_CLIENT_ID,
|
|
148
|
+
});
|
|
149
|
+
const payload = ticket.getPayload();
|
|
150
|
+
const userId = payload['sub'];
|
|
151
|
+
const email = payload['email'];
|
|
152
|
+
const name = payload['name'];
|
|
153
|
+
const picture = payload['picture'];
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Python**
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from google.oauth2 import id_token
|
|
160
|
+
from google.auth.transport import requests
|
|
161
|
+
|
|
162
|
+
request = requests.Request()
|
|
163
|
+
|
|
164
|
+
payload = id_token.verify_oauth2_token(
|
|
165
|
+
token,
|
|
166
|
+
request,
|
|
167
|
+
WEB_CLIENT_ID
|
|
168
|
+
)
|
|
169
|
+
user_id = payload['sub']
|
|
170
|
+
email = payload['email']
|
|
171
|
+
name = payload.get('name', '')
|
|
172
|
+
picture = payload.get('picture')
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Verification checks: JWT signature, `aud`, `exp`, `iss` (accounts.google.com).
|
|
176
|
+
|
|
177
|
+
For GIS integration, CSRF protection, and hosted domain validation, see [references/sign-in-with-google.md](references/sign-in-with-google.md).
|
|
178
|
+
|
|
179
|
+
### 4. JWT / Service Account
|
|
180
|
+
|
|
181
|
+
**Node.js**
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
const {JWT} = require('google-auth-library');
|
|
185
|
+
const keys = require('./service-account-key.json');
|
|
186
|
+
|
|
187
|
+
const client = new JWT({
|
|
188
|
+
email: keys.client_email,
|
|
189
|
+
key: keys.private_key,
|
|
190
|
+
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
|
|
191
|
+
});
|
|
192
|
+
const res = await client.fetch(url);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Python**
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from google.oauth2 import service_account
|
|
199
|
+
|
|
200
|
+
credentials = service_account.Credentials.from_service_account_file(
|
|
201
|
+
'service-account-key.json',
|
|
202
|
+
scopes=['https://www.googleapis.com/auth/cloud-platform']
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Or from a dict already loaded into memory:
|
|
206
|
+
credentials = service_account.Credentials.from_service_account_info(
|
|
207
|
+
info,
|
|
208
|
+
scopes=['https://www.googleapis.com/auth/cloud-platform']
|
|
209
|
+
)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 5. API Key
|
|
213
|
+
|
|
214
|
+
**Node.js**
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
const {OAuth2Client} = require('google-auth-library');
|
|
218
|
+
const client = new OAuth2Client({ apiKey: 'my-api-key' });
|
|
219
|
+
|
|
220
|
+
// Or via GoogleAuth:
|
|
221
|
+
const {GoogleAuth} = require('google-auth-library');
|
|
222
|
+
const auth = new GoogleAuth({
|
|
223
|
+
clientOptions: { apiKey: 'my-api-key' }
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Python**
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from googleapiclient.discovery import build
|
|
231
|
+
|
|
232
|
+
service = build('customsearch', 'v1', developerKey='my-api-key')
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 6. Token Refresh
|
|
236
|
+
|
|
237
|
+
**Node.js**
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
client.on('tokens', (tokens) => {
|
|
241
|
+
if (tokens.refresh_token) {
|
|
242
|
+
// Store refresh_token — only sent on first auth
|
|
243
|
+
}
|
|
244
|
+
console.log(tokens.access_token);
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Python**
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from google.auth.transport.requests import Request
|
|
252
|
+
|
|
253
|
+
if credentials.expired and credentials.refresh_token:
|
|
254
|
+
credentials.refresh(Request())
|
|
255
|
+
# credentials.token is the new access token
|
|
256
|
+
# credentials.expiry is the new expiration datetime
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Security Best Practices
|
|
260
|
+
|
|
261
|
+
- Never expose `client_secret` or service account keys in client-side code
|
|
262
|
+
- Always validate `state` parameter to prevent CSRF in OAuth flows
|
|
263
|
+
- Use `sub` (not `email`) as the unique user identifier from Google ID tokens
|
|
264
|
+
- Store `refresh_token` securely; it's only returned on first authorization
|
|
265
|
+
- Validate external credential configurations before use (check `token_url`, `service_account_impersonation_url` point to googleapis.com)
|
|
266
|
+
- Prefer Workload Identity Federation over service account keys for non-GCP environments
|
|
267
|
+
- For GIS: verify `g_csrf_token` with double-submit-cookie pattern
|
|
268
|
+
- **Python-specific**: reuse a single `google.auth.transport.requests.Request()` instance across verifications for connection pooling; do not create a new one per call in hot paths
|
|
269
|
+
|
|
270
|
+
## Reference Files
|
|
271
|
+
|
|
272
|
+
- **[OAuth 2.0 Web Server Flow](references/oauth2-web-server.md)** — Complete OAuth 2.0 flow: parameters, consent, token exchange, refresh, revocation, incremental auth, error handling (Node.js + Python)
|
|
273
|
+
- **[ADC & Service Accounts](references/adc-and-service-accounts.md)** — Application Default Credentials setup, service account keys, JWT, Compute credentials, environment configuration (Node.js + Python)
|
|
274
|
+
- **[Sign In with Google](references/sign-in-with-google.md)** — Google Identity Services (GIS), ID token verification, CSRF protection, One Tap, FedCM (Node.js + Python)
|
|
275
|
+
- **[Workload Identity Federation](references/workload-identity.md)** — AWS, Azure, OIDC/SAML federation, workforce identity, executable-sourced credentials (Node.js + Python)
|