From 419b11609fbf212ee6fa5b922b80d4f4f0eb0eae Mon Sep 17 00:00:00 2001 From: IT-WIBRC Date: Sat, 14 Feb 2026 11:50:23 +0100 Subject: [PATCH] doc(security): add remark made while working with api key in frontend app --- .husky/_/commit-msg | 3 +- .husky/_/pre-commit | 3 +- README.md | 15 ++++++ TODO.md | 4 ++ security/api-keys-tutorial-react.md | 76 +++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 security/api-keys-tutorial-react.md diff --git a/.husky/_/commit-msg b/.husky/_/commit-msg index 70bd3dd..16aae78 100755 --- a/.husky/_/commit-msg +++ b/.husky/_/commit-msg @@ -1 +1,2 @@ -npx --no-install commitlint --edit "$1" +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-commit b/.husky/_/pre-commit index 2312dc5..16aae78 100755 --- a/.husky/_/pre-commit +++ b/.husky/_/pre-commit @@ -1 +1,2 @@ -npx lint-staged +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/README.md b/README.md index 3cc422e..7ca63a6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ The goal is to foster consistent, maintainable, and testable code, serving as a - [Core Principles & General Advice](#core-principles--general-advice) - [Architectural Patterns & Design Choices](#architectural-patterns--design-choices) +- [Security & Best Practices](#security--best-practices) - [Language & Framework Specific Remarks](#language--framework-specific-remarks) - [Containerization & Deployment](#containerization--deployment) - [Utilities](#utilities) @@ -98,6 +99,18 @@ In-depth explanations of high-level architectural patterns and significant desig --- +## Security & Best Practices + +Focused on protecting application integrity and sensitive data in modern web environments. + +- [**API Key Security: Why `.env` is Not Enough for Frontend React**](./security/api-keys-tutorial-react.md) + - The "Tutorial Trap": Why client-side environment variables are still public. + - Using **Netlify Functions** (Serverless) as a secure backend proxy. + - Architectural benefits: Hiding sensitive logic and protecting API quotas. + - Practical implementation with React 19 hooks (`useTransition`, `useActionState`). + +--- + ## Language & Framework Specific Remarks Practical advice and common patterns specific to particular technologies. @@ -310,6 +323,8 @@ This section outlines the current directory and file structure for the `coding-r │ ├── pinia-store-encapsulation.md │ ├── reactivity-shallowref.md │ └── store-usage-scope.md +── security/ # Security patterns and tutorials +│ └── api-keys-tutorial-react.md # Deep dive into Serverless proxies ├── utils/ # General utility functions and classes │ ├── boolean-utils.ts │ ├── money-utils.ts diff --git a/TODO.md b/TODO.md index 48f0f35..a4282e2 100644 --- a/TODO.md +++ b/TODO.md @@ -46,3 +46,7 @@ ## CI/CD - [x] Guide to Containerizing a Modern JavaScript SPA (Vite) with a Multi-Stage Nginx Build + +## Security + +- [x] Securing API Keys with Serverless Proxies diff --git a/security/api-keys-tutorial-react.md b/security/api-keys-tutorial-react.md new file mode 100644 index 0000000..ad05471 --- /dev/null +++ b/security/api-keys-tutorial-react.md @@ -0,0 +1,76 @@ +# Securing API Keys with Serverless Proxies + +## 🛑 The Problem: The "Tutorial Trap" + +Most React tutorials instruct developers to store API keys in an `.env` file. While this prevents keys from being committed to GitHub, it is important to understand that **environment variables prefixed with `VITE_` or `REACT_APP_` are embedded into the client-side bundle.** + +Any key used in a client-side `fetch()` or `axios` call is still visible to anyone who opens the browser's "Network" tab. For a public API like **TMDB**, this exposes your quota and potentially your account to malicious actors. + +--- + +## 💡 The Solution: Netlify Functions as a Proxy + +Instead of calling the TMDB API directly from the React components, I architected a **Backend Proxy** using **Netlify Functions**. This ensures the API key never leaves the server environment. + +### 1. The Architecture + +- **Frontend:** Sends a request to a local endpoint: `/.netlify/functions/get-movies?query=...` +- **Serverless Function:** Resides on the server, retrieves the `TMDB_API_KEY` from the secure environment variables, and makes the actual request to TMDB. +- **Frontend:** Receives the clean JSON data without ever seeing the secret key. + +### 2. Implementation Comparison + +#### ❌ The Vulnerable Way (Client-Side) + +```javascript +// DON'T DO THIS: The key is leaked to the browser's Network tab! +const API_KEY = import.meta.env.VITE_TMDB_KEY; +const response = await fetch( + `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`, +); +``` + +#### ✅ The Secure Way (Netlify Function) + +Create a file at `netlify/functions/get-movies.js`: + +```javascript +exports.handler = async (event) => { + const API_KEY = process.env.TMDB_API_KEY; // Safely accessed on the server + const { query } = event.queryStringParameters; + + try { + const response = await fetch( + `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`, + ); + const data = await response.json(); + + return { + statusCode: 200, + body: JSON.stringify(data), + }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; +``` + +--- + +## ⚡ Enhancing UX with React 19 Hooks + +To make the search experience seamless while the proxy is fetching data, I implemented: + +- **`useTransition`**: Manages the UI state during the "search" transition, ensuring the input remains responsive even during network latency. +- **`useActionState`**: Handles the search form submission and state management natively, reducing boilerplate. +- **Skeleton Screens**: Improved perceived performance by replacing traditional loading spinners with layout placeholders that mimic the content structure. + +--- + +## 🛡️ Security Checklist + +As a trainer, I emphasize these three pillars for production-grade frontend engineering: + +1. **Never trust the client-side**: Sensitive logic and secrets must stay on the server. +2. **Proxy third-party APIs**: Always use serverless functions or a backend to protect your quotas and keys. +3. **Manage Network Resources**: Use `AbortController` to cancel pending requests when a user navigates away or types a new query rapidly. This prevents race conditions and saves bandwidth.