image

  • Hi! I’m Cuong.
  • I’m a Software Engineer working remotely in Virginia. I have been a full-stack developer with a front-end focus since 2014. Besides my passion for coding and solving technical problems, I enjoy traveling with my wife and our two little kids, Lyla and Aiden.

Declarative vs Imperative Programming

July 26, 2024 · 3 min

Validate Firebase JWT Token in Next.js middleware

While integrating Firebase Auth into one of my personal projects, I found out that the Firebase Admin SDK requires a Node.js environment, which doesn’t work with the Edge runtime used by Next.js middleware. The solution is to verify ID tokens using a third-party JWT library https://firebase.google.com/docs/auth/admin/verify-id-tokens. I’m using jose (JSON Object Signing and Encryption) module to verify ID tokens. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import { NextResponse } from 'next/server'; import { importX509, jwtVerify, JWTPayload } from 'jose'; const secretKey = process.env.JWT_SECRET_KEY; const firebaseProjectId = process.env.FIREBASE_PROJECT_ID; if (!secretKey || !firebaseProjectId) { throw new Error( 'Missing JWT_SECRET_KEY or FIREBASE_PROJECT_ID environment variable' ); } let publicKeysCache: Record<string, string> | null = null; const getPublicKeys = async (): Promise<Record<string, string>> => { if (publicKeysCache) { return publicKeysCache; } const res = await fetch( 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com' ); if (!res.ok) { throw new Error('Failed to fetch public keys'); } const publicKeys = await res.json(); publicKeysCache = publicKeys; return publicKeys; }; const verifyFirebaseJwt = async (firebaseJwt: string): Promise<JWTPayload> => { const publicKeys = await getPublicKeys(); const { payload } = await jwtVerify( firebaseJwt, async (header) => { const x509Cert = publicKeys[header.kid!]; if (!x509Cert) { throw new Error('Invalid key ID'); } return await importX509(x509Cert, 'RS256'); }, { issuer: `https://securetoken.google.com/${firebaseProjectId}`, audience: firebaseProjectId, algorithms: ['RS256'], } ); return payload; }; const createJsonResponse = (data: any, status: number): NextResponse => { return new NextResponse(JSON.stringify(data), { status, headers: { 'Content-Type': 'application/json', }, }); }; export async function middleware(req: any): Promise<NextResponse> { const token = req.headers.get('Authorization')?.split('Bearer ')[1]; if (!token) { return createJsonResponse({ error: 'Unauthorized' }, 401); } try { await verifyFirebaseJwt(token); return NextResponse.next(); } catch (error) { console.error('JWT verification failed:', error); return createJsonResponse({ error: 'Unauthorized' }, 401); } } export const config = { matcher: ['/api/:path*'], }; Fetching Public Keys: The getPublicKeys function fetches the public keys from the Google API. These keys are used to verify the JWT tokens. ...

June 25, 2024 · 3 min

Weekend Project: Setup Github Container Registry and Github Actions for CI/CD with DigitalOcean droplets

For this weekend’s fun project, let’s setup Github Actions and Github Container Registry so we can do CI/CD with our NodeJS project hosted on DigitalOcean. The goal is to have Github Actions create a new Docker image when we push to master, deploy the image to ghcr.io, ssh to the server, download the image and build the container. Create the app/repo Let’s create a new public repo on Github named nodejs-playground, add a simple app to this repo: ...

June 22, 2024 · 5 min

Weekend Project: Deploy multiple Docker containers on a DigitalOcean droplet

Each weekend I want to try out small projects using different tech stacks/technologies. This week let’s deploy a Linux box on DigitalOcean and set it up so we can run multiple Docker containers for future weekend projects. 1. Setup Docker and Nginx Install docker: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04 Check if docker is running 1 sudo systemctl status docker press q to exit Install nginx https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04 if you run 1 2 sudo ufw allow 'Nginx HTTP' sudo ufw status and it shows Status: inactive - that means the firewall is inactive. Enable the firewall by running ...

June 16, 2024 · 5 min

Understanding the differences between || and ?? operators in JavaScript

We often run into scenarios where we need to provide default values for variables. Two operators that can help with this are the logical OR (||) and the nullish coalescing (??) operators. While they might appear to behave similarly, they serve distinct purposes and understanding their differences is import for writing bug-free code. An Example Consider the following code snippet: 1 2 3 4 5 let userPreference = null; let defaultPreference = "dark mode"; let theme = userPreference || defaultPreference; console.log(theme); // Output: "dark mode" In this example, the || operator is used to provide a default value if userPreference is null or undefined. The code works as expected and outputs "dark mode". Now, let’s tweak userPreference to an empty string: ...

June 8, 2024 · 2 min