Skip to content

Admin handler reads process.env directly instead of runtimeConfig, causing 404 on platforms where build-time env vars aren't available at runtime #384

@byrne-sbt

Description

@byrne-sbt

Environment

  • nuxt-studio: 1.4.0
  • nuxt: 4.3.1
  • nitropack: latest (with aws-amplify preset)
  • Deployment platform: AWS Amplify (Gen 2)
  • Node.js: 22.x

Version

1.4.0

Reproduction

A minimal StackBlitz is not possible since this requires deploying to a platform where build-time env vars don't propagate to the server runtime (e.g. AWS Amplify). However, it can be reproduced locally:

  1. Create a Nuxt project with nuxt-studio configured with GitHub OAuth:
    // nuxt.config.ts
    export default defineNuxtConfig({
      modules: ['nuxt-studio'],
      studio: {
        repository: { provider: 'github', owner: 'you', repo: 'your-repo', branch: 'main' },
      },
    })
  2. Set STUDIO_GITHUB_CLIENT_ID and STUDIO_GITHUB_CLIENT_SECRET in .env
  3. Run nuxt build
  4. Start the built server without the env vars in the environment:
    # Simulates a platform where build-time env vars aren't forwarded to runtime
    env -u STUDIO_GITHUB_CLIENT_ID -u STUDIO_GITHUB_CLIENT_SECRET \
      node .output/server/index.mjs
  5. Visit /_studio

Expected: The login page loads (since the auth config was baked into runtimeConfig at build time).

Actual: 404 — "No authentication provider found"

Description

The /_studio admin route handler checks process.env directly at runtime to determine which auth providers are available:

// dist/module/runtime/server/routes/admin.js
const hasGithub = process.env.STUDIO_GITHUB_CLIENT_ID && "github";
const hasGitlab = process.env.STUDIO_GITLAB_APPLICATION_ID && "gitlab";
const hasGoogle = process.env.STUDIO_GOOGLE_CLIENT_ID && "google";
const hasSSO = process.env.STUDIO_SSO_URL && process.env.STUDIO_SSO_CLIENT_ID && process.env.STUDIO_SSO_CLIENT_SECRET && "sso";
const providers = [hasGithub, hasGitlab, hasGoogle, hasSSO].filter(Boolean);
if (providers.length === 0) {
  throw createError({ statusCode: 404, message: "No authentication provider found" });
}

This is inconsistent with the rest of the module:

  • The module setup reads these same env vars at build time and stores them in runtimeConfig.studio.auth.github.clientId / .clientSecret
  • The GitHub auth handler (auth/github.get) correctly uses useRuntimeConfig().studio.auth.github
  • The repository config is also accessed via useRuntimeConfig() at runtime

Only the admin handler bypasses runtimeConfig. On platforms like AWS Amplify, environment variables are available during nuxt build (so runtimeConfig is populated correctly), but are not forwarded to the Lambda runtime. This causes the admin handler to 404 even though auth is fully configured.

Suggested fix

Replace the process.env reads in the admin handler with useRuntimeConfig():

export default eventHandler((event) => {
  const studioConfig = useRuntimeConfig().studio;

  const hasGithub = studioConfig.auth?.github?.clientId && "github";
  const hasGitlab = studioConfig.auth?.gitlab?.applicationId && "gitlab";
  const hasGoogle = studioConfig.auth?.google?.clientId && "google";
  const hasSSO = studioConfig.auth?.sso?.serverUrl
    && studioConfig.auth?.sso?.clientId
    && studioConfig.auth?.sso?.clientSecret
    && "sso";

  // ... rest unchanged
});

Workaround

A Nitro plugin that bridges runtimeConfig values back to process.env on server startup:

// server/plugins/studio-env.ts
declare const process: { env: Record<string, string | undefined> };

export default defineNitroPlugin(() => {
  const config = useRuntimeConfig();
  const studioAuth = (config as Record<string, unknown>).studio as
    | { auth?: { github?: { clientId?: string; clientSecret?: string } } }
    | undefined;

  if (!studioAuth?.auth) return;

  const envMap: Record<string, string | undefined> = {
    STUDIO_GITHUB_CLIENT_ID: studioAuth.auth.github?.clientId,
    STUDIO_GITHUB_CLIENT_SECRET: studioAuth.auth.github?.clientSecret,
  };

  for (const [key, value] of Object.entries(envMap)) {
    if (value && !process.env[key]) {
      process.env[key] = value;
    }
  }
});

Additional context

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions