Repository navigation
GoogleCertificateManager
Typed Google Cloud Certificate Manager client for Deno, Bun, Node.js and
Cloudflare Workers: create, read, list and delete Google-managed TLS
certificates and certificate map entries, and follow the long-running
operations they return, with service-account auth signed by Web Crypto. No
gcloud, no Application Default Credentials and no
@google-cloud/certificate-manager SDK.
The connect is built for one job: a TLS certificate per customer domain behind a global external Application Load Balancer. The load balancer's HTTPS proxy carries a certificate map. For each customer domain you:
- Create a managed certificate for the hostname. With load-balancer authorization (the default: no DNS authorization), Google validates the domain once its A/AAAA records point at the load balancer.
- Create a map entry binding the hostname to that certificate in the map.
-
Read the certificate while it provisions.
managed.stateisPROVISIONING, thenACTIVE.FAILEDmeans Google gave up: delete the certificate and create a new one. - When the domain goes away, delete the map entry, then the certificate.
Creates and deletes return a long-running operation. waitForOperation
polls one until it finishes or a deadline passes. A failed operation throws
the same typed error a synchronous refusal would.
import {
GoogleCertificateManager,
GoogleCertificateManagerError,
hostnameToResourceId,
} from '@tundraconnect/google-certificate-manager';
const client = new GoogleCertificateManager({
auth: {
type: 'CUSTOM',
clientEmail: 'certs@my-project.iam.gserviceaccount.com',
privateKey: '-----BEGIN PRIVATE KEY-----\n...',
},
projectId: 'my-project',
certificateMapId: 'customer-domains',
});
const hostname = 'go.example.com';
const id = hostnameToResourceId(hostname, { prefix: 'brevily' });
try {
await client.waitForOperation(
await client.createCertificate({ certificateId: id, domains: [hostname] }),
);
} catch (err) {
// A retry after a lost answer: the certificate already exists.
if (
!(err instanceof GoogleCertificateManagerError &&
err.code === 'ALREADY_EXISTS')
) throw err;
}
await client.createCertificateMapEntry({
entryId: id,
hostname,
certificates: [id],
});
const certificate = await client.getCertificate(id);
console.log(certificate.managed?.state); // 'PROVISIONING' until DNS points at the LBCertificate and map-entry ids must be lowercase RFC 1035 labels: a letter
first, then letters, digits or hyphens, at most 63 characters.
hostnameToResourceId derives one from a hostname. It slugs the hostname
and always appends an 8-hex-digit hash, because the readable part alone
collides: my-site.co.uk and my.site-co.uk both slug to my-site-co-uk.
The result is deterministic, so the certificate and its map entry can share
it, and a later delete can recompute it from the hostname alone.
hostnameToResourceId('go.example.com'); // 'go-example-com-' + 8 hex digits
hostnameToResourceId('Go.Example.COM.'); // the same id
hostnameToResourceId('*.example.com'); // 'wildcard-example-com-…'const cert = await client.getCertificate(id);
if (cert.managed?.state === 'PROVISIONING') {
for (const attempt of cert.managed.authorizationAttemptInfo ?? []) {
// e.g. 'go.example.com' 'FAILED' 'CONFIG': the A record is not on the LB yet
console.log(attempt.domain, attempt.state, attempt.failureReason);
}
}Every failure is a GoogleCertificateManagerError. Branch on code. The
ones a domain flow usually needs:
| Code | Meaning | transient |
|---|---|---|
ALREADY_EXISTS |
The resource is already there. Treat a retried create as success. | no |
NOT_FOUND |
The resource does not exist. Treat a retried delete as success. | no |
FAILED_PRECONDITION |
e.g. deleting a certificate a map entry still uses. | no |
PERMISSION_DENIED |
Missing IAM role, or the Certificate Manager API is not enabled. | no |
QUOTA_EXCEEDED |
A resource-count quota is exhausted. Delete resources or raise it. | no |
RATE_LIMITED |
A per-minute rate limit. Retry with backoff. | yes |
SERVICE_UNAVAILABLE |
A 5xx from Google, or from the token endpoint. | yes |
TIMEOUT |
No answer within the client's timeout. |
yes |
NETWORK_ERROR |
The request failed before any response. | yes |
OPERATION_TIMEOUT |
waitForOperation hit its deadline. The operation may still finish. |
yes |
The full list is in Errors.
-
{ type: 'CUSTOM', clientEmail, privateKey, scope? }: a service account. Takeclient_emailandprivate_keyfrom its downloaded JSON key. The client signs an RS256 JWT with Web Crypto, exchanges it athttps://oauth2.googleapis.com/tokenand caches the access token until a minute before it expires. Concurrent requests share one exchange. The scope defaults tohttps://www.googleapis.com/auth/cloud-platform. -
{ type: 'BEARER', token }: an access token you already have. The client never refreshes it.
The service account needs roles/certificatemanager.editor (or the
certificatemanager.certs.*, certificatemanager.certmapentries.* and
certificatemanager.operations.get permissions) on the project, and the
Certificate Manager API must be enabled.
Your tests don't need to fake HTTP. Have your code take a
GoogleCertificateManager instance and pass in a stand-in that returns the
shapes from @tundraconnect/google-certificate-manager/schemas, or throws a
real error:
import { GoogleCertificateManagerError } from '@tundraconnect/google-certificate-manager/errors';
const exists = new GoogleCertificateManagerError('ALREADY_EXISTS', {
status: 409,
});
console.log(exists.code, exists.transient); // 'ALREADY_EXISTS' falseTo exercise the client itself against a fake transport, subclass it and
reassign the protected _fetch.
| Topic | Description |
|---|---|
| API | Client configuration, methods and operation polling |
| Errors | Error codes, mapping and diagnostic metadata |
| Schemas | Public Guardian schemas and types |
- Certificate Manager REST reference
- Deploy a Google-managed certificate with load balancer authorization
- Certificate maps
- Quotas and limits
Deno:
deno add jsr:@tundraconnect/google-certificate-managerBun:
bunx jsr add @tundraconnect/google-certificate-managerNode.js:
npx jsr add @tundraconnect/google-certificate-managerMIT. Part of Tundra Connect, typed vendor API clients for Deno, Bun, Node.js and Cloudflare Workers.
- Algolia
- AzureBlob
- CloudflareDNS
- CloudflareEmail
- CloudflareSaaS
- CloudflareTurnstile
- CoinGecko
- Discord
- DodoPayments
- GCS
- GoogleAnalytics
- GoogleCertificateManager
- GoogleWebRisk
- Kalshi
- ntfy
- OpenExchange
- OpenWeatherMap
- PayPal
- Polymarket
- Razorpay
- Resend
- S3
- SendGrid
- Sentry
- Slack
- Stripe
- Telegram
- Twilio
- UpstashRedis
- URLhaus