> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bonnes Pratiques de Sécurité

> Sécurisez votre intégration avec une authentification et une gestion des données appropriées

## Sécurité des clés API

### Stockage

<Warning>
  Ne commitez jamais les clés API dans le contrôle de version ou ne les exposez pas dans du code côté client.
</Warning>

```javascript theme={null}
// ❌ Bad: Hardcoded in source code
const API_KEY = "sk_live_abc123";

// ✅ Good: Use environment variables
const API_KEY = process.env.FLEXY_API_KEY;
```

### Variables d'environnement

```bash theme={null}
# .env file
FLEXY_API_KEY=sk_live_your_key_here
FLEXY_SANDBOX_KEY=sk_test_your_sandbox_key
API_BASE_URL=https://api.oneclickdz.com
```

```javascript theme={null}
// Load environment variables
require("dotenv").config();

const apiKey = process.env.FLEXY_API_KEY;
```

### Rotation des clés

```javascript theme={null}
// Support multiple keys for zero-downtime rotation
const API_KEYS = {
  primary: process.env.FLEXY_API_KEY_PRIMARY,
  secondary: process.env.FLEXY_API_KEY_SECONDARY,
};

async function callApiWithRotation(endpoint, data) {
  try {
    return await callApi(endpoint, data, API_KEYS.primary);
  } catch (error) {
    if (error.status === 401) {
      // Try secondary key
      return await callApi(endpoint, data, API_KEYS.secondary);
    }
    throw error;
  }
}
```

## Application du HTTPS

```javascript theme={null}
// Always use HTTPS
const API_BASE_URL = "https://api.oneclickdz.com";

// Reject self-signed certificates in production
const axios = require("axios");
const https = require("https");

const client = axios.create({
  baseURL: API_BASE_URL,
  httpsAgent: new https.Agent({
    rejectUnauthorized: process.env.NODE_ENV === "production",
  }),
});
```

## Validation des requêtes

```javascript theme={null}
// Validate all inputs before sending to API
const Joi = require("joi");

const mobileTopupSchema = Joi.object({
  plan_code: Joi.string().required(),
  MSSIDN: Joi.string()
    .pattern(/^0[567][0-9]{8}$/)
    .required(),
  amount: Joi.number()
    .min(50)
    .max(5000)
    .when("plan_code", {
      is: Joi.string().pattern(/^DYN/),
      then: Joi.required(),
      otherwise: Joi.forbidden(),
    }),
  reference: Joi.string().max(100).required(),
});

function validateTopupRequest(data) {
  const { error, value } = mobileTopupSchema.validate(data);
  if (error) {
    throw new Error(`Validation error: ${error.message}`);
  }
  return value;
}
```

## Gestion des données sensibles

### Ne journalisez pas les données sensibles

```javascript theme={null}
// ❌ Bad: Logs API key
console.log("Request:", {
  headers: { "X-Access-Token": apiKey },
  body: data,
});

// ✅ Good: Redact sensitive info
function sanitizeLog(data) {
  const sanitized = { ...data };
  if (sanitized.headers?.["X-Access-Token"]) {
    sanitized.headers["X-Access-Token"] = "***REDACTED***";
  }
  return sanitized;
}

console.log("Request:", sanitizeLog(request));
```

### Protégez les numéros de téléphone

```javascript theme={null}
// Mask phone numbers in logs/UI
function maskPhone(phone) {
  if (phone.length !== 10) return phone;
  return phone.slice(0, 4) + "****" + phone.slice(-2);
}

console.log("Top-up sent to:", maskPhone("0551234567")); // 0551****67
```

### Sécurisez les codes de cartes

```javascript theme={null}
// Never log full card codes
function maskCardCode(code) {
  if (code.length <= 4) return "****";
  return "****" + code.slice(-4);
}

// Store securely
await db.orders.create({
  data: {
    userId: user.id,
    cardCode: encrypt(cardCode), // Encrypt sensitive data
    cardCodeMasked: maskCardCode(cardCode),
  },
});
```

## Limitation du débit

```javascript theme={null}
// Implement client-side rate limiting
const rateLimit = require("express-rate-limit");

const apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // Max 60 requests per minute
  message: "Too many requests, please try again later",
});

app.use("/api/topup", apiLimiter, topupHandler);
```

## Liste blanche d'IP

<Info>
  Contactez le support pour mettre votre serveur sur liste blanche d'IP pour une sécurité supplémentaire.
</Info>

```javascript theme={null}
// Make requests from whitelisted IPs only
const WHITELISTED_IPS = ["192.168.1.100", "10.0.0.50"];

function isWhitelisted(ip) {
  return WHITELISTED_IPS.includes(ip);
}

app.use((req, res, next) => {
  const clientIp = req.ip;
  if (!isWhitelisted(clientIp)) {
    return res.status(403).json({ error: "Forbidden" });
  }
  next();
});
```

## Journalisation des audits

```javascript theme={null}
// Log all API interactions for audit
async function auditLog(event, data) {
  await db.auditLogs.create({
    data: {
      timestamp: new Date(),
      event,
      userId: data.userId,
      action: data.action,
      ipAddress: data.ip,
      userAgent: data.userAgent,
      requestId: data.requestId,
      success: data.success,
      // Don't log sensitive data
      metadata: sanitize(data.metadata),
    },
  });
}

// Usage
await auditLog("topup_sent", {
  userId: user.id,
  action: "SEND_MOBILE_TOPUP",
  ip: req.ip,
  userAgent: req.get("user-agent"),
  requestId: response.requestId,
  success: true,
});
```

## Messages d'erreur

```javascript theme={null}
// Don't expose internal details in error messages
function getSafeErrorMessage(error) {
  // Internal errors
  if (error.status >= 500) {
    return {
      message: "An error occurred. Please try again later.",
      code: "INTERNAL_ERROR",
      requestId: error.requestId, // Include for support
    };
  }

  // Client errors - be specific but safe
  return {
    message: error.message,
    code: error.code,
  };
}
```

## Configuration sécurisée

```javascript theme={null}
// Séparer les configurations sandbox/production
const config = {
  sandbox: {
    apiKey: process.env.FLEXY_SANDBOX_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: true,
    logLevel: "debug",
  },
  production: {
    apiKey: process.env.FLEXY_API_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: false,
    logLevel: "error",
  },
};

const env = process.env.NODE_ENV || "sandbox";
const currentConfig = config[env];
```

## Sécurité des dépendances

```bash theme={null}
# Auditer régulièrement les dépendances
npm audit

# Mettre à jour les packages vulnérables
npm audit fix

# Utiliser des outils comme Snyk
npm install -g snyk
snyk test
```

## Chiffrement des données au repos

```javascript theme={null}
// Chiffrer les données sensibles avant de les stocker
const crypto = require("crypto");

const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // Clé 32 octets
const IV_LENGTH = 16;

function encrypt(text) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let encrypted = cipher.update(text);
  encrypted = Buffer.concat([encrypted, cipher.final()]);
  return iv.toString("hex") + ":" + encrypted.toString("hex");
}

function decrypt(text) {
  const parts = text.split(":");
  const iv = Buffer.from(parts.shift(), "hex");
  const encrypted = Buffer.from(parts.join(":"), "hex");
  const decipher = crypto.createDecipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  return decrypted.toString();
}

// Utilisation
const cardCode = "1234-5678-9012";
const encrypted = encrypt(cardCode);
await db.orders.create({ data: { cardCode: encrypted } });
```

## Liste de contrôle de sécurité

<Steps>
  <Step title="Clés API">
    ✓ Stockées dans des variables d'environnement ✓ Non committées dans le contrôle de version ✓ Renouvelées périodiquement
  </Step>

  <Step title="HTTPS">
    ✓ Toutes les requêtes utilisent HTTPS ✓ Validation des certificats activée
  </Step>

  <Step title="Validation des entrées">
    ✓ Toutes les entrées validées avant les appels API ✓ Validation par schéma en place
  </Step>

  <Step title="Journalisation">
    ✓ Les données sensibles ne sont pas journalisées ✓ Journaux d'audit activés ✓ IDs de requête tracés
  </Step>

  <Step title="Limitation du débit">
    ✓ Limitation côté client ✓ Logique de réessai avec backoff
  </Step>

  <Step title="Protection des données">
    ✓ Données sensibles chiffrées au repos ✓ Numéros de téléphone masqués dans les journaux ✓ Codes de cartes sécurisés
  </Step>
</Steps>

## Résumé des bonnes pratiques

<CardGroup cols={2}>
  <Card title="Ne jamais exposer les clés" icon="key">
    Utiliser des variables d'environnement
  </Card>

  <Card title="Toujours utiliser HTTPS" icon="lock">
    Sécuriser toutes les communications
  </Card>

  <Card title="Tout valider" icon="circle-check">
    Vérifier les entrées avant d'envoyer
  </Card>

  <Card title="Chiffrer les données sensibles" icon="shield">
    Protéger les données au repos
  </Card>
</CardGroup>

## Liens connexes

<CardGroup cols={2}>
  <Card title="Authentification" href="/fr/authentication">
    Configuration des clés API
  </Card>

  <Card title="Gestion des erreurs" href="/fr/api-reference/error-handling">
    Gérer les erreurs en toute sécurité
  </Card>
</CardGroup>
