Skip to content
Learni
View all tutorials
Google Cloud Platform

How to Implement Google Cloud KMS for Encryption in 2026

Lire en français

Introduction

Google Cloud Key Management Service (KMS) is a managed service for creating, managing, and using cryptographic keys to encrypt data at rest or in transit. In 2026, with growing regulations like GDPR and zero-trust requirements, KMS is essential for cloud-native applications.

This intermediate tutorial walks you through implementing KMS in a Node.js app: from key creation to integration in a Next.js API. You'll learn to encrypt/decrypt sensitive data like tokens or configs using the official client API. Every step includes complete, functional code tested locally with Application Default Credentials (ADC).

Why it matters: KMS handles automatic key rotation, audits via Cloud Audit Logs, and native integration with Cloud Storage, BigQuery, or Compute Engine. By the end, you'll have a secure REST API ready for production. Estimated time: 30 minutes.

Prerequisites

  • Active Google Cloud Platform (GCP) account with billing enabled.
  • gcloud CLI installed and configured (gcloud init).
  • Node.js 20+ and npm/yarn.
  • Next.js 15+ project (created via npx create-next-app@latest with App Router).
  • Basic knowledge of TypeScript and cryptography (symmetric/asymmetric).

Install Dependencies

terminal
npm init -y
npm install @google-cloud/kms typescript ts-node @types/node
npm install -D next@latest react react-dom @types/react @types/react-dom

# Pour un projet Next.js complet (optionnel mais recommandé)
npx create-next-app@latest mon-app-kms --typescript --app --tailwind --eslint --src-dir --import-alias "@/*"
cd mon-app-kms
npm install @google-cloud/kms

This script initializes a Node.js or Next.js project and installs the official @google-cloud/kms client. ts-node lets you run TypeScript directly. For Next.js, it creates a boilerplate project with App Router for later API integration. Verify with npm ls @google-cloud/kms.

Set Up GCP Authentication

KMS requires secure authentication. Use Application Default Credentials (ADC) for smooth local development: they prioritize service account or gcloud user credentials. Enable the KMS API in your GCP project via console.cloud.google.com/apis/library/kms.googleapis.com.

Authenticate and Enable the API

terminal
gcloud auth application-default login

gcloud services enable cloudkms.googleapis.com --project=VOTRE_PROJECT_ID

gcloud kms locations list --project=VOTRE_PROJECT_ID

The gcloud auth application-default login command sets up ADC for the Node.js client. Replace VOTRE_PROJECT_ID with your GCP project ID (e.g., my-project-123). locations list checks availability (use 'global' or 'europe'). Avoid static API keys in production; prefer service accounts.

Create a Key Ring and Key

terminal
export PROJECT_ID=VOTRE_PROJECT_ID
export LOCATION=global
export KEYRING_NAME=my-keyring
export KEY_NAME=my-key

gcloud kms keyrings create $KEYRING_NAME \
  --location=$LOCATION \
  --project=$PROJECT_ID

gcloud kms keys create $KEY_NAME \
  --location=$LOCATION \
  --keyring=$KEYRING_NAME \
  --purpose=encryption \
  --project=$PROJECT_ID

gcloud kms keys list --keyring=$KEYRING_NAME --location=$LOCATION --project=$PROJECT_ID

This creates a key ring (logical container) and a symmetric key for encryption (purpose=encryption). list confirms creation. Use 'global' for simplicity, or 'europe' for EU compliance. Keys are HSM-backed by default in 2026, resistant to extraction.

Encrypt and Decrypt Data

Now for the client code. The KMS client wraps plaintext into base64 ciphertext, which you can store in a database. Imagine encrypting a JWT token before storing it in Cloud SQL.

TypeScript Encryption Script

kms-encrypt.ts
import {KeyManagementServiceClient} from '@google-cloud/kms';

const client = new KeyManagementServiceClient();
const projectId = 'VOTRE_PROJECT_ID';
const locationId = 'global';
const keyRingId = 'my-keyring';
const keyId = 'my-key';
const name = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

async function encrypt(plaintext: string): Promise<string> {
  const [result] = await client.encrypt({
    name,
    plaintext: Buffer.from(plaintext),
  });
  return result.ciphertext!.toString('base64');
}

(async () => {
  const encrypted = await encrypt('Mon secret super sensible');
  console.log('Ciphertext:', encrypted);
})();

This script creates a KMS client, references the key via an ARN-like path, and encrypts plaintext (as Buffer) to base64 ciphertext. Run with npx ts-node kms-encrypt.ts. Replace the IDs. Pitfall: Always use Buffer to avoid UTF-8 encoding issues.

TypeScript Decryption Script

kms-decrypt.ts
import {KeyManagementServiceClient} from '@google-cloud/kms';

const client = new KeyManagementServiceClient();
const projectId = 'VOTRE_PROJECT_ID';
const locationId = 'global';
const keyRingId = 'my-keyring';
const keyId = 'my-key';
const name = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

async function decrypt(ciphertext: string): Promise<string> {
  const [result] = await client.decrypt({
    name,
    ciphertext: Buffer.from(ciphertext, 'base64'),
  });
  return result.plaintext!.toString();
}

(async () => {
  const ciphertext = 'CiQA...'; // Remplacez par output de encrypt
  const decrypted = await decrypt(ciphertext);
  console.log('Plaintext:', decrypted);
})();

Symmetric to encryption, this code decrypts base64 ciphertext back to plaintext. Note Buffer.from(..., 'base64'). Test by copying the output from encrypt.ts. Common error: Key protections (e.g., rotation) disable decrypt on old versions.

Integrate KMS into a Next.js API

Advantage: Next.js App Router serverless functions integrate seamlessly with KMS via ADC in dev, or Workload Identity in production on Cloud Run/Vercel.

Encryption API Route (Next.js)

app/api/encrypt/route.ts
import {KeyManagementServiceClient} from '@google-cloud/kms';
import {NextRequest, NextResponse} from 'next/server';

const client = new KeyManagementServiceClient();
const projectId = process.env.GCP_PROJECT_ID || 'VOTRE_PROJECT_ID';
const locationId = 'global';
const keyRingId = 'my-keyring';
const keyId = 'my-key';
const name = client.cryptoKeyPath(projectId!, locationId, keyRingId, keyId);

export async function POST(req: NextRequest) {
  try {
    const {plaintext} = await req.json();
    if (!plaintext) {
      return NextResponse.json({error: 'Plaintext requis'}, {status: 400});
    }
    const [result] = await client.encrypt({name, plaintext: Buffer.from(plaintext)});
    return NextResponse.json({ciphertext: result.ciphertext!.toString('base64')});
  } catch (error) {
    return NextResponse.json({error: 'Erreur chiffrement'}, {status: 500});
  }
}

This POST /api/encrypt route receives JSON {plaintext}, encrypts it via KMS, and returns ciphertext. Use an env var for projectId. Test with curl or Postman. Secure in production with API keys or IAM.

Decryption API Route (Next.js)

app/api/decrypt/route.ts
import {KeyManagementServiceClient} from '@google-cloud/kms';
import {NextRequest, NextResponse} from 'next/server';

const client = new KeyManagementServiceClient();
const projectId = process.env.GCP_PROJECT_ID || 'VOTRE_PROJECT_ID';
const locationId = 'global';
const keyRingId = 'my-keyring';
const keyId = 'my-key';
const name = client.cryptoKeyPath(projectId!, locationId, keyRingId, keyId);

export async function POST(req: NextRequest) {
  try {
    const {ciphertext} = await req.json();
    if (!ciphertext) {
      return NextResponse.json({error: 'Ciphertext requis'}, {status: 400});
    }
    const [result] = await client.decrypt({name, ciphertext: Buffer.from(ciphertext, 'base64')});
    return NextResponse.json({plaintext: result.plaintext!.toString()});
  } catch (error) {
    return NextResponse.json({error: 'Erreur déchiffrement'}, {status: 500});
  }
}

Mirror decryption route POST /api/decrypt with input validation. Run npm run dev and test at localhost:3000/api/decrypt. Pitfall: Without try/catch, IAM errors (e.g., kms.keys.decrypt permission) crash the app.

Best Practices

  • Automatic Rotation: Enable with gcloud kms keys update --rotation-period=90d to renew keys without downtime.
  • Minimal Permissions: Use roles like roles/cloudkms.cryptoKeyEncrypterDecrypter on service accounts.
  • Ciphertext Storage: Base64 in DB (Cloud SQL/PostgreSQL); limit size (4KB max per op).
  • Audits: Enable Cloud Audit Logs to track all KMS access.
  • Multi-Region: For HA, duplicate key rings in 'europe-west1' and 'us-central1'.

Common Errors to Avoid

  • Wrong Region: Key in 'global' inaccessible from 'europe' without replicas.
  • Missing ADC: 401 error; rerun gcloud auth application-default login.
  • Plaintext Too Large: KMS limits 64KB; chunk large files with hybrid envelope.
  • No Validation: Always sanitize inputs to prevent injections in plaintext.

Next Steps