Advanced

Runtime Configuration

Runtime config and secrets management for Nuxt Umbu

Learn about runtime configuration in Nuxt Umbu, including secrets management, environment variables, and secure configuration practices.

Overview

Nuxt Umbu leverages Nuxt's runtime configuration system to manage sensitive data like API credentials, secrets, and environment-specific settings. This ensures sensitive information never leaks to the client bundle.

Runtime Config vs Public Config

Runtime Config (Server-Side Only)

Runtime config is only available on the server and never exposed to the client:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // Server-side only
    secret: {
      password: {
        client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    }
  }
})

Public Runtime Config (Client-Side)

Public config is exposed to the client:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      // Available on both client and server
      auth: {
        provider: 'sanctum',
        cookie: {
          prefix: 'auth.',
          options: {
            httpOnly: false,
            secure: false,
            sameSite: 'Lax'
          }
        }
      }
    }
  }
})

Passport Secrets Configuration

For Passport provider, you must configure secrets in runtime config:

Required Structure

runtimeConfig: {
  secret: {
    [strategyName]: {
      client_id: string | number,
      client_secret: string,
      grant_type: 'password' | 'authorization_code'
    }
  }
}

Example Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  auth: {
    provider: 'passport',
    strategies: {
      password: {
        endpoints: {
          login: { url: '/oauth/token', method: 'post' },
          user: { url: '/api/user', method: 'get' }
        },
        redirect: {
          login: '/login',
          logout: '/'
        }
      }
    }
  },
  runtimeConfig: {
    secret: {
      password: {
        client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    }
  }
})

Multiple Strategies

runtimeConfig: {
  secret: {
    password: {
      client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
      client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
      grant_type: 'password'
    },
    social: {
      client_id: process.env.NUXT_AUTH_SOCIAL_CLIENT_ID,
      client_secret: process.env.NUXT_AUTH_SOCIAL_CLIENT_SECRET,
      grant_type: 'authorization_code'
    }
  }
}

Environment Variables

Using .env Files

Create environment files for different environments:

# .env
NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_client_secret

# .env.production
NUXT_AUTH_PASSWORD_CLIENT_ID=prod_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=prod_client_secret

# .env.development
NUXT_AUTH_PASSWORD_CLIENT_ID=dev_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=dev_client_secret

Accessing Environment Variables

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    secret: {
      password: {
        client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    }
  }
})

Environment-Specific Config

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    secret: {
      password: {
        client_id: process.env.NODE_ENV === 'production' 
          ? process.env.NUXT_AUTH_PASSWORD_CLIENT_ID 
          : process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NODE_ENV === 'production'
          ? process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET
          : process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    }
  }
})

Accessing Runtime Config

Server-Side Access

// server/api/config.get.ts
export default defineEventHandler((event) => {
  const config = useRuntimeConfig()
  const secret = config.secret.password
  
  return {
    clientId: secret.client_id
    // Never expose client_secret!
  }
})

Client-Side Access (Public Config Only)

// In components
const config = useRuntimeConfig()
const authConfig = config.public.auth

console.log(authConfig.provider) // 'sanctum' or 'passport'

Validation

The module automatically validates runtime config:

Secret Validation

For Passport provider, the module validates:

  1. Secret exists
    if (!runtimeConfig.secret) {
      logger.error('Missing "runtimeConfig.secret" in nuxt.config.ts')
    }
    
  2. Secret structure is valid
    function isValidSecretConfig(secret: unknown): secret is Record<string, AuthSecretConfig> {
      return typeof secret === 'object' && secret !== null && 
             Object.values(secret).every(config => 
               typeof config === 'object' && 
               config !== null &&
               'client_id' in config &&
               'client_secret' in config &&
               'grant_type' in config
             )
    }
    
  3. Strategy correspondence
    Object.entries(runtimeConfig.secret).forEach(([key, config]) => {
      if (!options.strategies[key]) {
        logger.error(`Strategy "${key}" found in secret but not in strategies`)
      }
    })
    

Common Validation Errors

Missing runtimeConfig.secret

Error: Missing "runtimeConfig.secret" in nuxt.config.ts

Solution:

runtimeConfig: {
  secret: {
    password: {
      client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
      client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
      grant_type: 'password'
    }
  }
}

Invalid secret structure

Error: Invalid "runtimeConfig.secret" structure in nuxt.config.ts

Solution: Ensure each secret has client_id, client_secret, and grant_type.

Strategy not found

Error: Strategy "password" found in secret but not in options.strategies

Solution: Ensure strategy names match between strategies and secret.

Security Best Practices

Never Expose Secrets

// ❌ BAD - Exposes secret to client
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      secret: {
        client_secret: 'secret'  // This will be in client bundle!
      }
    }
  }
})

// ✅ GOOD - Secret stays on server
export default defineNuxtConfig({
  runtimeConfig: {
    secret: {
      client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET
    }
  }
})

Use Environment Variables

# .env
NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_secret_here

# Add to .gitignore
.env
.env.local
.env.*.local

Validate at Build Time

// nuxt.config.ts
if (!process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET) {
  throw new Error('NUXT_AUTH_PASSWORD_CLIENT_SECRET environment variable is required')
}

Use Different Secrets per Environment

# .env.development
NUXT_AUTH_PASSWORD_CLIENT_SECRET=dev_secret

# .env.staging
NUXT_AUTH_PASSWORD_CLIENT_SECRET=staging_secret

# .env.production
NUXT_AUTH_PASSWORD_CLIENT_SECRET=prod_secret

Common Patterns

Multi-Environment Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  auth: {
    provider: 'passport',
    cookie: {
      prefix: process.env.NODE_ENV === 'production' ? '__Secure-' : 'auth.',
      options: {
        secure: process.env.NODE_ENV === 'production',
        httpOnly: process.env.NODE_ENV === 'production',
        sameSite: process.env.NODE_ENV === 'production' ? 'Strict' : 'Lax'
      }
    }
  },
  runtimeConfig: {
    secret: {
      password: {
        client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    }
  }
})

Feature Flag Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      auth: {
        provider: process.env.AUTH_PROVIDER || 'sanctum',
        enable2FA: process.env.ENABLE_2FA === 'true'
      }
    }
  }
})

Dynamic Endpoint Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      auth: {
        apiBase: process.env.API_BASE_URL || 'https://api.example.com'
      }
    }
  }
})

// Use in strategy configuration
strategies: {
  default: {
    endpoints: {
      login: { 
        url: `${useRuntimeConfig().public.auth.apiBase}/login`,
        method: 'post' 
      }
    }
  }
}

Deployment Configuration

Vercel

# Set environment variables in Vercel dashboard
NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_client_secret

Netlify

# Set in Netlify environment variables
NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_client_secret

Docker

# Dockerfile
ENV NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
# Secret injected at runtime via docker-compose.yml or deployment platform
# docker-compose.yml
services:
  app:
    environment:
      - NUXT_AUTH_PASSWORD_CLIENT_ID=${NUXT_AUTH_PASSWORD_CLIENT_ID}
      - NUXT_AUTH_PASSWORD_CLIENT_SECRET=${NUXT_AUTH_PASSWORD_CLIENT_SECRET}

Traditional Server

# Set environment variables
export NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
export NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_client_secret

# Or use .env file
cp .env.example .env
# Edit .env with your values

Troubleshooting

Config Not Loading

Problem: Runtime config not available

Solution:

  1. Restart dev server after config changes
  2. Check that config is in nuxt.config.ts
  3. Verify environment variables are set
  4. Check for typos in config keys

Secrets Not Working

Problem: Passport secrets not being used

Solution:

  1. Verify runtimeConfig.secret structure
  2. Check that strategy names match
  3. Ensure environment variables are set
  4. Check module logs for validation errors

Environment Variables Not Available

Problem: process.env values are undefined

Solution:

  1. Ensure .env file exists
  2. Check that .env is in project root
  3. Verify variable names match
  4. Restart dev server after adding variables

Public Config Exposing Secrets

Problem: Sensitive data in client bundle

Solution:

  1. Move secrets from public to root runtimeConfig
  2. Check browser network tab for exposed data
  3. Use nuxi build and inspect bundle
  4. Review runtimeConfig.public contents

Best Practices Summary

  • Always use runtime config for secrets: Never put secrets in public config
  • Use environment variables: Keep secrets out of code
  • Validate at build time: Fail fast if config is missing
  • Different environments: Use different secrets per environment
  • Never commit secrets: Add .env to .gitignore
  • Rotate secrets regularly: Update secrets periodically
  • Use strong secrets: Generate random, complex secrets
  • Monitor for leaks: Check bundles and network traffic
  • Document config: Document required environment variables
  • Use type safety: Leverage TypeScript for config validation

Configuration Template

Complete Example

// nuxt.config.ts
export default defineNuxtConfig({
  // Auth module configuration (public)
  auth: {
    provider: process.env.AUTH_PROVIDER || 'sanctum',
    cookie: {
      prefix: process.env.NODE_ENV === 'production' ? '__Secure-' : 'auth.',
      options: {
        httpOnly: process.env.NODE_ENV === 'production',
        secure: process.env.NODE_ENV === 'production',
        sameSite: process.env.NODE_ENV === 'production' ? 'Strict' : 'Lax',
        priority: 'high'
      }
    },
    strategies: {
      default: {
        endpoints: {
          login: { url: '/login', method: 'post' },
          user: { url: '/api/user', method: 'get' },
          logout: { url: '/logout', method: 'post' }
        },
        redirect: {
          login: '/login',
          logout: '/',
          home: '/dashboard'
        }
      }
    }
  },

  // Runtime configuration
  runtimeConfig: {
    // Server-side only (secrets)
    secret: {
      password: {
        client_id: process.env.NUXT_AUTH_PASSWORD_CLIENT_ID,
        client_secret: process.env.NUXT_AUTH_PASSWORD_CLIENT_SECRET,
        grant_type: 'password'
      }
    },

    // Public (client and server)
    public: {
      auth: {
        provider: process.env.AUTH_PROVIDER || 'sanctum',
        apiBase: process.env.API_BASE_URL || 'https://api.example.com'
      }
    }
  }
})

Environment File Template

# .env.example
AUTH_PROVIDER=sanctum
API_BASE_URL=https://api.example.com

# Passport (if using passport provider)
NUXT_AUTH_PASSWORD_CLIENT_ID=your_client_id
NUXT_AUTH_PASSWORD_CLIENT_SECRET=your_client_secret

# Sanctum (if using sanctum provider)
SANCTUM_CSRF_URL=/sanctum/csrf-cookie