# SvelteKit et les Server Actions pour écrire dans WordPress sans exposer de clé

> Utilisez les actions de formulaire de SvelteKit comme proxy sécurisé entre le front et l'API REST authentifiée de WordPress, sans jamais transmettre d'identifiants au navigateur.

- Auteur : Clément Hadrot
- Publié le : 2023-02-06
- Mis à jour le : 2023-02-06
- Catégorie : Headless &amp; API
- URL : https://wpmoderne.dev.wordpress-developpement.fr/headless/sveltekit-form-actions-proxy-wordpress-sans-cle-api/

## L’essentiel

- Le navigateur n'a jamais accès au mot de passe d'application
- Les actions de formulaire tournent côté serveur, jamais côté client
- Un seul fichier +page.server.js concentre toute la logique sensible

Un projet associatif nous a demandé un formulaire d'adhésion en ligne, capable de créer directement une fiche de membre dans WordPress via l'API REST, sans passerelle tierce ni service externe. Le piège classique de ce genre de besoin est de placer, par facilité, les identifiants d'authentification WordPress directement dans le code du front, accessible à quiconque ouvre les outils de développement du navigateur. Ce tutoriel ne traite pas de SvelteKit en lecture seule, un usage plus simple déjà couvert ailleurs sur ce blog, mais spécifiquement de l'écriture sécurisée via ses actions de formulaire.

## Étape 1 : comprendre pourquoi un appel direct depuis le navigateur pose problème

Une requête `POST` vers `/wp-json/wp/v2/membre` depuis un composant Svelte classique nécessiterait un mot de passe d'application WordPress dans l'en-tête `Authorization`, visible en clair dans l'onglet réseau du navigateur de n'importe quel visiteur curieux. Même en le récupérant dynamiquement depuis une variable d'environnement, celle-ci finirait de toute façon incluse dans le code JavaScript envoyé au navigateur si elle est préfixée pour être accessible côté client.

## Étape 2 : créer une action de formulaire côté serveur

SvelteKit propose un mécanisme natif, les `actions`, définies dans un fichier `+page.server.js` qui ne s'exécute jamais dans le navigateur, uniquement sur le serveur Node.js qui fait tourner l'application :

```
// src/routes/adhesion/+page.server.js
import { WP_API_URL, WP_APP_USER, WP_APP_PASSWORD } from '$env/static/private'

export const actions = {
  default: async ({ request }) => {
    const donnees = await request.formData()

    const identifiants = Buffer.from(
      `${WP_APP_USER}:${WP_APP_PASSWORD}`
    ).toString('base64')

    const reponse = await fetch(`${WP_API_URL}/wp-json/wp/v2/membre`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Basic ${identifiants}`,
      },
      body: JSON.stringify({
        title: donnees.get('nom'),
        status: 'publish',
        acf: {
          email: donnees.get('email'),
          date_adhesion: new Date().toISOString(),
        },
      }),
    })

    if (!reponse.ok) {
      return { succes: false, erreur: 'Impossible de créer la fiche adhérent' }
    }

    return { succes: true }
  },
}
```

Le préfixe `$env/static/private` est essentiel ici : contrairement à `$env/static/public`, ces variables ne sont jamais incluses dans le bundle JavaScript envoyé au navigateur, elles restent réservées au code exécuté côté serveur.

> L'essentiel à retenir : Le navigateur n'a jamais accès au mot de passe d'application ; Les actions de formulaire tournent côté serveur, jamais côté client ; Un seul fichier +page.server.js concentre toute la logique sensible

## Étape 3 : relier le formulaire côté client à cette action

Le composant Svelte n'a besoin de connaître ni l'URL de l'API WordPress, ni le moindre identifiant. Il se contente de soumettre un formulaire HTML standard, éventuellement progressivement amélioré avec `use:enhance` pour éviter un rechargement complet de page :

```
<script>
  import { enhance } from '$app/forms'
  export let form
</script>

<form method="POST" use:enhance>
  <input name="nom" required />
  <input name="email" type="email" required />
  <button type="submit">Adhérer</button>
</form>

{#if form?.succes}
  <p>Adhésion enregistrée, merci !</p>
{:else if form?.erreur}
  <p>{form.erreur}</p>
{/if}
```

## Étape 4 : restreindre les droits du compte utilisé côté serveur

Le compte WordPress associé au mot de passe d'application ne doit disposer que des capacités strictement nécessaires à cette action précise, jamais d'un compte administrateur complet. Un rôle personnalisé, créé via `add_role()`, avec uniquement la capacité de créer des entrées du type de contenu `membre`, limite les dégâts possibles en cas de compromission du serveur d'hébergement du front lui-même.

## Étape 5 : ajouter une protection anti-robot

Un champ invisible de type « pot de miel », vérifié côté serveur dans l'action elle-même, complète le dispositif contre les soumissions automatisées, sans dépendre d'un service tiers de type CAPTCHA pour ce cas d'usage à faible enjeu :

```
if (donnees.get('site_web_confirmation')) {
  return { succes: false, erreur: 'Requête invalide' }
}
```

## Ce que cette approche apporte

- Aucun identifiant WordPress ne transite jamais vers le navigateur, à aucun moment du parcours.
- La validation des données peut être renforcée côté serveur avant l'envoi à WordPress, sans dépendre uniquement de la validation HTML côté client, facilement contournable.
- Le compte utilisé peut être restreint à une seule capacité précise, réduisant la surface d'attaque en cas de fuite du mot de passe d'application.

> Un formulaire qui écrit dans WordPress depuis un front headless ne devrait jamais faire confiance au navigateur pour porter le moindre secret : le serveur applicatif du front est le seul endroit sûr pour ça.

## En résumé

Les actions de formulaire de SvelteKit offrent un proxy naturel et sécurisé entre un front headless et l'API REST authentifiée de WordPress, sans infrastructure supplémentaire ni service tiers. Le principe reste simple à retenir : tout ce qui touche à un identifiant sensible doit rester dans un fichier qui ne s'exécute jamais dans le navigateur, jamais dans un composant client, aussi tentant que cela paraisse pour aller plus vite.
