Как скрыть переменные окружения в рантайме для браузера в Nuxt
Что проверяют
Понимаете ли вы, что в браузер уходит всё, что попало в клиентский бандл или в payload страницы, и спрятать там секрет нельзя в принципе. Следом обычно спрашивают, чем runtimeConfig отличается от переменных, вшитых при сборке, и как поменять значение без пересборки.
Как отвечать
Начните с тезиса: скрыть переменную от браузера можно только одним способом, не отправлять её туда. В Nuxt 3 и 4 для этого есть runtimeConfig в nuxt.config.ts:
- корневые ключи
runtimeConfig: доступны только на сервере, вserver/api, серверных плагинах и при SSR. На клиентеuseRuntimeConfig()их просто не вернёт; runtimeConfig.public: сериализуется в payload страницы и видна любому, кто откроет её исходник. Сюда кладут только то, что и так публично: базовый URL API, ключ аналитики;- переопределение в рантайме: значения подменяются переменными окружения с префиксом
NUXT_, напримерNUXT_API_SECRETдляapiSecretиNUXT_PUBLIC_API_BASEдляpublic.apiBase. Работает, только если ключ объявлен в конфиге, хотя бы пустой строкой; .env: читается в dev и приnuxi build, но в продакшене нет. Там переменные задаёт окружение: контейнер, systemd, платформа.
Если клиенту нужен результат запроса с секретным ключом, делаете серверный роут в server/api: он читает useRuntimeConfig(event), ходит во внешний сервис и отдаёт клиенту только данные. Ключ из сервера не выходит.
Хорошо упомянуть и Nuxt 2: там были publicRuntimeConfig и privateRuntimeConfig, а опция env и префикс NUXT_ENV_ вшивали значения в бандл на этапе сборки. В Nuxt 3 это заменил единый runtimeConfig.
Где спотыкаются
Считают, что обфускация или минификация прячет ключ. Строка остаётся в бандле, её находят поиском во вкладке Sources или в запросах на Network за минуту.
Кладут секрет в runtimeConfig.public «временно, для отладки» и забывают. Проверка простая: открыть исходник страницы и поискать значение в payload.
Путают защиту API и защиту секрета. Строгий CORS ограничивает браузерные запросы с чужих сайтов, но не мешает вызвать API через curl, а утёкший ключ он не отзывает.