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)

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay