Skip to content
This repository was archived by the owner on Nov 3, 2025. It is now read-only.

Conversation

@diberry
Copy link

@diberry diberry commented Apr 24, 2025

This application appears to use the OpenAI secrets in the client application. Is that true and why is that necessary? That seems unsecure.

How is Remix/Vite building the secrets into the static client?

Typically I only have the backend URL added to the static front end build and all the secrets are on the backend.

There is still an issue with the infra that the OpenAI key and endpoint aren't actually in the Key Vault. That needs to be fixed.

@diberry diberry requested a review from glaucia86 as a code owner April 24, 2025 19:08
@glaucia86
Copy link
Contributor

This application appears to use the OpenAI secrets in the client application. Is that true and why is that necessary? That seems unsecure.

How is Remix/Vite building the secrets into the static client?

Typically I only have the backend URL added to the static front end build and all the secrets are on the backend.

There is still an issue with the infra that the OpenAI key and endpoint aren't actually in the Key Vault. That needs to be fixed.

Makes totally sense your thought Dina. I will take a look about it and then make some changes right now! Thanks for pointing out this!

@glaucia86 glaucia86 self-assigned this Apr 24, 2025
@glaucia86 glaucia86 added bug Something isn't working enhancement New feature or request labels Apr 24, 2025
@glaucia86
Copy link
Contributor

Hi @diberry, thanks for catching that. I made a resource about it and it’s important to clarify how openai-service.ts runs entirely on the server even though it lives under lib/services and not in the server/ folder. Here’s a detailed, step-by-step explanation:


1. Project Structure

/
├── app/                  ← Remix front-end + routes
│   ├── routes/
│   │   ├── _index.tsx
│   │   └── generate.tsx  ← UI + ActionFunction combined
│   └── components/…
├── lib/
│   └── services/
│       └── openai-service.ts  ← our OpenAI client code
├── server/               ← server-only code (Express setup, middleware, etc.)
│   └── src/…
└── infra/…

Even though openai-service.ts is outside of server/, it is never imported by any React component or client-side code.


2. Imported Only in Remix Actions (Server)

In app/routes/generate.tsx you’ll see:

import { ActionFunction } from "@remix-run/node";
import { azureOpenAIService } from "../../lib/services/openai-service";

export const action: ActionFunction = async ({ request }) => {
  // we call our OpenAI service here
  const generated = await azureOpenAIService.generateMicroblogContent(/* … */);
  return new Response(JSON.stringify({ success: true, content: generated }));
};

// Below is the React component that renders the form and triggers the action
export default function Generate() { /* … */ }
  • An ActionFunction runs only on the server.
  • Anything inside that function—including the import of azureOpenAIService—is never shipped to the browser.

3. How Remix Separates Bundles

Remix (and its Vite build) produces two distinct outputs:

  1. Server Bundle: contains loaders, actions, import "dotenv/config", openai-service.ts, and all Node-only code.
  2. Client Bundle: contains only your React components, CSS, and client-side code.

Remix automatically tree-shakes out any module used exclusively by loaders/actions, so it never ends up in the client bundle.


4. Why openai-service.ts Stays Secure

  • It begins with import "dotenv/config"; and reads process.env.*. Those APIs exist only in Node.js. If this file were accidentally included in the client bundle, the build would fail—so Remix keeps it server-only.
  • No React component or browser code ever references azureOpenAIService, so there’s zero risk of exposing your API key.

5. Additional Best Practices

  • Use the .server.ts suffix: Renaming the file to openai-service.server.ts makes it explicit. Remix will never include files with .server. in the client bundle, regardless of import that might creep in.
  • Dynamic import inside the action: As an extra safeguard, you can do:
    export const action: ActionFunction = async ({ request }) => {
      const { azureOpenAIService } = await import("../../lib/services/openai-service");
      // …
    };
    That ensures the entire module is loaded only at runtime on the server.

In Summary

  1. Even though it lives in lib/services, openai-service.ts is used only by a Remix Action and therefore runs strictly on the server.
  2. Remix automatically separates server-only code from the client bundle, so none of it reaches the browser.
  3. Your OpenAI API key remains protected in the Node.js environment and is never exposed to end users.

Hope this clarifies how Remix handles that file and keeps your credentials safe! Let me know if you have any other questions. 😊

@glaucia86 glaucia86 mentioned this pull request Apr 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants