DEV Community

Cover image for API Keys y Variables de Entorno en Astro: Guía Completa de Seguridad
Joaquín Gutiérrez
Joaquín Gutiérrez

Posted on

API Keys y Variables de Entorno en Astro: Guía Completa de Seguridad

Cuando desarrollamos aplicaciones web con Astro, frecuentemente necesitamos interactuar con APIs y servicios externos. Manejar las credenciales y claves de API de forma segura es crucial para proteger nuestras aplicaciones. En esta guía, exploraremos las mejores prácticas para gestionar API keys y variables de entorno en proyectos Astro.

Variables de Entorno en Astro

Configuración Básica

En Astro, las variables de entorno se manejan de forma similar a otros frameworks modernos. Primero, creamos un archivo .env en la raíz de nuestro proyecto:

# .env
PUBLIC_API_URL=https://api.ejemplo.com
PRIVATE_API_KEY=tu_clave_secreta
DATABASE_URL=postgresql://usuario:password@localhost:5432/db
Enter fullscreen mode Exit fullscreen mode

Para TypeScript, es recomendable crear un archivo env.d.ts para tipar nuestras variables:

/// <reference types="astro/client" />
interface ImportMetaEnv {
  readonly DATABASE_URL: string;
  readonly PRIVATE_API_KEY: string;
  readonly PUBLIC_API_URL: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
Enter fullscreen mode Exit fullscreen mode

Accediendo a las Variables

En Astro, podemos acceder a las variables de entorno de diferentes formas según el contexto:

---
// En archivos .astro
const apiKey = import.meta.env.PRIVATE_API_KEY;
const publicUrl = import.meta.env.PUBLIC_API_URL;
---
Enter fullscreen mode Exit fullscreen mode
// En archivos .ts o .js
const apiKey = import.meta.env.PRIVATE_API_KEY;
Enter fullscreen mode Exit fullscreen mode

Seguridad en el Frontend

Variables Públicas vs Privadas

Astro sigue una convención importante para las variables de entorno:

  • PUBLIC_*: Accesibles en el cliente y el servidor
  • Sin prefijo PUBLIC_: Solo accesibles en el servidor
# .env
PUBLIC_API_URL=https://api.publica.com    # ✅ Visible en el cliente
PRIVATE_API_KEY=secreto123                # ⛔ Solo servidor
Enter fullscreen mode Exit fullscreen mode

Protegiendo Claves Sensibles

Para manejar APIs que requieren autenticación, debemos crear endpoints serverless:

// src/pages/api/data.ts
export async function GET() {
  try {
    const response = await fetch('https://api.externa.com/data', {
      headers: {
        'Authorization': `Bearer ${import.meta.env.PRIVATE_API_KEY}`
      }
    });

    const data = await response.json();
    return new Response(JSON.stringify(data), {
      status: 200,
      headers: {
        'Content-Type': 'application/json'
      }
    });
  } catch (error) {
    return new Response(JSON.stringify({ error: 'Error al obtener datos' }), {
      status: 500
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Mejores Prácticas

1. Validación de Variables de Entorno

Implementa una función de validación al inicio de tu aplicación:

// src/utils/validateEnv.ts
export function validateEnv() {
  const requiredEnvVars = [
    'DATABASE_URL',
    'PRIVATE_API_KEY',
    'PUBLIC_API_URL'
  ];

  for (const envVar of requiredEnvVars) {
    if (!import.meta.env[envVar]) {
      throw new Error(`La variable de entorno ${envVar} es requerida`);
    }
  }
}

// src/pages/index.astro
---
import { validateEnv } from '../utils/validateEnv';

if (import.meta.env.MODE === 'development') {
  validateEnv();
}
---
Enter fullscreen mode Exit fullscreen mode

2. Gestión de Múltiples Entornos

Crea diferentes archivos para cada entorno:

.env                # Variables por defecto
.env.development    # Variables de desarrollo
.env.production     # Variables de producción
.env.local          # Variables locales (ignoradas en git)
Enter fullscreen mode Exit fullscreen mode

3. Template de Variables de Entorno

Proporciona un archivo .env.example:

# .env.example
PUBLIC_API_URL=https://api.ejemplo.com
PRIVATE_API_KEY=tu_clave_aqui
DATABASE_URL=postgresql://usuario:password@localhost:5432/db
Enter fullscreen mode Exit fullscreen mode

4. Configuración de Git

Asegúrate de incluir los archivos sensibles en .gitignore:

# .gitignore
.env
.env.local
.env.*.local
Enter fullscreen mode Exit fullscreen mode

Integración con Servicios Externos

Ejemplo con Stripe

// src/pages/api/create-payment.ts
import Stripe from 'stripe';

export async function POST({ request }) {
  const stripe = new Stripe(import.meta.env.STRIPE_SECRET_KEY);

  try {
    const { amount, currency } = await request.json();

    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency
    });

    return new Response(JSON.stringify({ clientSecret: paymentIntent.client_secret }), {
      status: 200
    });
  } catch (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      status: 400
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Ejemplo con Firebase

// src/lib/firebase.ts
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = {
  apiKey: import.meta.env.PUBLIC_FIREBASE_API_KEY,
  authDomain: import.meta.env.PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: import.meta.env.PUBLIC_FIREBASE_PROJECT_ID,
};

export const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
Enter fullscreen mode Exit fullscreen mode

Despliegue y CI/CD

Configuración en Vercel

# Configurar variables en Vercel CLI
vercel env add PRIVATE_API_KEY
vercel env add DATABASE_URL
Enter fullscreen mode Exit fullscreen mode

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Deploy to Vercel
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
          PRIVATE_API_KEY: ${{ secrets.PRIVATE_API_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: vercel deploy --prod --token=$VERCEL_TOKEN
Enter fullscreen mode Exit fullscreen mode

Consejos de Seguridad Adicionales

  1. Rotación de Claves: Implementa un sistema para rotar periódicamente las claves API
// src/utils/rotateApiKey.ts
async function rotateApiKey() {
  const currentKey = import.meta.env.PRIVATE_API_KEY;
  const expirationDays = 30;

  // Lógica para verificar la edad de la clave
  // Implementar rotación si es necesario
}
Enter fullscreen mode Exit fullscreen mode
  1. Monitoreo de Uso: Implementa logging para detectar uso indebido
// src/middleware/apiLogger.ts
export async function apiLogger(request, apiName) {
  console.log(`[${new Date().toISOString()}] API Call: ${apiName}`);
  // Implementar logging más detallado según necesidades
}
Enter fullscreen mode Exit fullscreen mode

El manejo seguro de API keys y variables de entorno es crucial para cualquier aplicación web moderna. Siguiendo estas mejores prácticas en Astro, podemos:

  • Mantener nuestras credenciales seguras
  • Separar configuraciones por entorno
  • Implementar validaciones robustas
  • Integrar servicios externos de forma segura

Top comments (0)