feat(backend): add Open Food Facts authentication support
Run Tests on Branches / Detect Changes (push) Successful in 11s
Run Tests on Branches / Frontend Tests (push) Has been cancelled
Run Tests on Branches / Frontend Mobile Tests (push) Has been cancelled
Run Tests on Branches / Backend Tests (push) Has been cancelled

- Add OFF_USERNAME and OFF_PASSWORD env vars
- Use Basic Auth when credentials are provided
- Improves rate limits for authenticated requests
- Auth is optional (works without credentials)
This commit is contained in:
Antoni Nuñez Romeu
2026-07-13 16:28:34 +02:00
parent ee23f61057
commit f1b0eab11d
2 changed files with 24 additions and 0 deletions
+5
View File
@@ -19,3 +19,8 @@ VAPID_SUBJECT=mailto:admin@example.com
# Expo Push Notifications (mobile). Get token from:
# https://expo.dev/accounts/[username]/settings/access-tokens
EXPO_ACCESS_TOKEN=
# Open Food Facts (optional, improves rate limits)
# Register at: https://world.openfoodfacts.org/
OFF_USERNAME=
OFF_PASSWORD=
+19
View File
@@ -4,6 +4,20 @@ import redisClient from './redis-client.js';
const OFF_API_BASE = 'https://world.openfoodfacts.org';
const CACHE_TTL = 3600;
// Open Food Facts authentication (optional, improves rate limits)
const OFF_USERNAME = process.env.OFF_USERNAME;
const OFF_PASSWORD = process.env.OFF_PASSWORD;
function getOffAuth() {
if (OFF_USERNAME && OFF_PASSWORD) {
return {
username: OFF_USERNAME,
password: OFF_PASSWORD,
};
}
return null;
}
export function transformOFFProduct(offProduct) {
if (!offProduct || !offProduct._id || !offProduct.product_name) {
return null;
@@ -53,6 +67,7 @@ export async function searchBabyProducts(query) {
}
console.log(`Fetching from OFF API: ${searchTerm}`);
const auth = getOffAuth();
const response = await axios.get(`${OFF_API_BASE}/cgi/search.pl`, {
params: {
search_terms: searchTerm,
@@ -63,6 +78,7 @@ export async function searchBabyProducts(query) {
},
timeout: 10000,
validateStatus: (status) => status === 200,
...(auth && { auth }),
});
// Check if response is actually JSON (OFF sometimes returns HTML on error)
@@ -108,8 +124,11 @@ export async function getBabyProductDetails(barcode) {
}
console.log(`Fetching OFF product details: ${barcode}`);
const auth = getOffAuth();
const response = await axios.get(`${OFF_API_BASE}/api/v2/product/${barcode}.json`, {
timeout: 10000,
validateStatus: (status) => status === 200,
...(auth && { auth }),
});
if (response.data && response.data.product) {