Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
AI & KI NachrichtenIs the AI industry really ready to slow down?(20.09.2026 um 20:56 Uhr)
Sichere ProgrammierungThe audio bugs nobody warns you about when you build a mobile looper(20.09.2026 um 20:18 Uhr)
Sichere ProgrammierungA Successful Response Can Still Belong to the Wrong Screen(20.09.2026 um 20:23 Uhr)
Sichere ProgrammierungGzip 1.15 fixes a wrong-file deletion race(20.09.2026 um 20:32 Uhr)
Sichere ProgrammierungWhen SQL Has Nothing to Say: Handling NULLs(20.09.2026 um 20:35 Uhr)
Sichere ProgrammierungWeb Programming in C++ with WFC(20.09.2026 um 20:37 Uhr)
AI & KI NachrichtenIs the AI industry really ready to slow down?(20.09.2026 um 20:56 Uhr)
Sichere ProgrammierungThe audio bugs nobody warns you about when you build a mobile looper(20.09.2026 um 20:18 Uhr)
Sichere ProgrammierungA Successful Response Can Still Belong to the Wrong Screen(20.09.2026 um 20:23 Uhr)
Sichere ProgrammierungGzip 1.15 fixes a wrong-file deletion race(20.09.2026 um 20:32 Uhr)
Sichere ProgrammierungWhen SQL Has Nothing to Say: Handling NULLs(20.09.2026 um 20:35 Uhr)
Sichere ProgrammierungWeb Programming in C++ with WFC(20.09.2026 um 20:37 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Rolling a Google Service Account JWT in Node.js without the googleapis package

Reagiere als Erste:r — dein Feedback zählt!

The googleapis npm package is the default answer for calling Google APIs from Node.js. It works, but it installs around 380KB and brings in over 450 transitive dependencies. For a single API used in a CI script — the Search Console URL Inspection API — the underlying auth flow is simple enough to handle directly.

I built scripts/gsc-inspect.mjs to check index status for published URLs. It's about 60 lines, uses three Node.js built-ins (crypto, fetch, URL), and adds zero packages to the repo.

The service account auth flow

Google's service account auth follows RFC 7523 — the JWT Bearer Grant profile of OAuth2. The steps are:

  1. Construct a JWT with your service account's client_email and private key
  2. POST that JWT to https://oauth2.googleapis.com/token
  3. Receive a short-lived access token (valid 3600 seconds)
  4. Use the access token as a Bearer header on API requests

The JWT claims:

const claims = {
  iss: sa.client_email,
  scope: "https://www.googleapis.com/auth/webmasters.readonly",
  aud: "https://oauth2.googleapis.com/token",
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000) + 3600,
};

One thing worth knowing upfront: use the webmasters scope, not searchconsole. The URL Inspection API requires webmasters.readonly — the newer searchconsole scope doesn't grant access to it.

Signing with Node's crypto module

Base64url encoding is the only non-obvious part. Standard base64 needs three character replacements to become base64url:

import { createSign } from "node:crypto";

const b64url = (obj) =>
  Buffer.from(JSON.stringify(obj))
    .toString("base64")
    .replace(/=+$/, "")     // strip padding
    .replace(/\+/g, "-")    // + → -
    .replace(/\//g, "_");   // / → _

const unsigned = `${b64url(header)}.${b64url(claims)}`;
const signer = createSign("RSA-SHA256");
signer.update(unsigned);
signer.end();
const sig = signer
  .sign(sa.private_key)
  .toString("base64")
  .replace(/=+$/, "")
  .replace(/\+/g, "-")
  .replace(/\//g, "_");
const jwt = `${unsigned}.${sig}`;

sa.private_key is the RSA private key string from the service account JSON you download from Google Cloud Console. It's already in PKCS#8 PEM format (-----BEGIN PRIVATE KEY-----...), so createSign("RSA-SHA256").sign(key) works directly. No key conversion or external library needed.

Exchanging the JWT for an access token

The token exchange is a URL-encoded form POST:

const res = await fetch("https://oauth2.googleapis.com/token", {
  method: "POST",
  headers: { "content-type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    assertion: jwt,
  }),
});
if (!res.ok) {
  const body = await res.text();
  throw new Error(`Token exchange failed (${res.status}): ${body.slice(0, 300)}`);
}
const { access_token } = await res.json();

The error handling matters here. The invalid_grant error from Google often includes a useful error_description like "Token must expire within 3600 seconds of the issued time" or "Service account not found". Logging the raw response body — truncated to 300 chars — surfaces that directly without digging through a framework's error abstraction.

Calling the URL Inspection endpoint

With the token in hand:

const res = await fetch(
  "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      inspectionUrl: url,
      siteUrl: `https://${siteHost}/`,
    }),
  }
);
const data = await res.json();
console.log(JSON.stringify({
  url,
  coverageState: data.inspectionResult?.indexStatusResult?.coverageState,
  lastCrawlTime: data.inspectionResult?.indexStatusResult?.lastCrawlTime,
}));

The siteUrl field must match a property you've verified in Google Search Console — and it must be the exact string you registered (trailing slash matters). After verifying three domains with Cloudflare DNS TXT records, you also need to add the service account's client_email as a Search Console user (Owner or Full user) before the API will respond to requests.

The coverageState values include INDEXED, SUBMITTED_AND_INDEXED, CRAWLED_CURRENTLY_NOT_INDEXED, and a few others. For post-publish verification, one JSON line per URL is enough — grep-able, loggable in CI without any special tooling.

When not to use this approach

Raw implementation is appropriate for a single API in a CI script. It's less appropriate when:

  • You're calling multiple Google APIs and want unified auth handling
  • You need automatic token refresh across long-running processes
  • You need retry logic, batching, or type-safe API responses
  • You're shipping production server code where a well-tested library is worth its weight

For this project, the tradeoff is clear: I'm running one CI pipeline across five automated workflows and avoiding unnecessary npm additions. Sixty lines of readable, inspectable code beats 450 transitive dependencies for a use case this narrow.

The implementation is also useful as documentation. The googleapis package abstracts the JWT flow so thoroughly that many developers don't know what's actually happening in the auth exchange. Understanding the raw flow — JWT → token endpoint → Bearer header — makes debugging auth failures faster regardless of what library you end up using.

The sites are still new. I'll publish actual per-URL index coverage data in 30 days once there's something meaningful to report.

Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Rolling a Google Service Account JWT in Node.js without the googleapis package

Thematisch verwandte Begriffe: Rolling, Google, Service, Account · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93956 | A flaw has been found in olivier-ls PHP-FTS up to 1.1.2. Affected by thi…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick