- 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
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. ...
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: ...
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 ...
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: ...