Aller au contenu

Intégrer Wajub avec React

L'emplacement de la clé secrète dans une application React ou Next.js, et pourquoi elle ne change jamais de place.

Toutes les intégrations React et Next.js suivent la même structure, quel que soit le mode choisi. Une fois cette structure comprise, les différences entre la redirection, l'intégration et les champs personnalisés ne relèvent plus de l'architecture, mais seulement de l'affichage.

Cette page présente cette structure. Le code complet de chaque mode se trouve sur la page React et Next.js. Une recette complète avec un véritable formulaire et une page de retour est disponible dans Checkout avec Next.js App Router.

La règle commune à tous les modes

La clé secrète ne quitte jamais le serveur. Elle ne figure ni dans une prop, ni dans une constante intégrée au bundle, ni dans un composant client qui « s'exécute uniquement lors du build ».

Il ne s'agit pas d'un simple conseil. Wajub applique cette règle à l'entrée de la plateforme.

Le navigateur ne détient donc jamais la clé et n'en a pas besoin. Voici ce qu'il reçoit à la place.

Les quatre étapes, identiques dans chaque mode

Relisez la dernière ligne. Lorsque le client vous annonce une réussite, il ne s'agit que d'une affirmation. Le webhook constitue le fait. La livraison de la commande dépend toujours du webhook, jamais d'un callback onSuccess.

Implémentation avec Next.js

Une Server Action constitue la version correcte la plus courte. La directive 'use server' définit la frontière. Le corps de la fonction n'est jamais intégré au bundle du navigateur. La clé ne peut donc pas lui parvenir.

app/actions/checkout.ts
'use server';

import { Wajub } from '@wajub/node';

const wajub = new Wajub({ apiKey: process.env.WAJUB_SECRET_KEY! });

export async function startCheckout(orderId: string) {
  const order = await db.orders.find(orderId);

  const payment = await wajub.payments.create(
    {
      amount: order.amount,
      currency: order.currency,
      customer: { email: order.email },
      reference: order.reference,
      callback: `${process.env.APP_URL}/orders/${order.id}/return`,
    },
    { idempotencyKey: order.reference },
  );

  await db.orders.update(order.id, { payment_id: payment.id });

  return { url: payment.authorization_url };
}

Notez que l'action accepte uniquement un identifiant de commande. Le montant provient de votre base de données, pas de l'argument. Un client qui peut définir son propre prix finira par le faire.

Le composant qui appelle cette action est un composant client ordinaire. Il n'importe jamais le SDK.

app/checkout/PayButton.tsx
'use client';

import { useTransition } from 'react';
import { startCheckout } from '@/app/actions/checkout';

export function PayButton({ orderId }: { orderId: string }) {
  const [pending, start] = useTransition();

  return (
    <button
      disabled={pending}
      onClick={() =>
        start(async () => {
          const { url } = await startCheckout(orderId);
          window.location.href = url;
        })
      }
    >
      {pending ? 'Starting…' : 'Pay'}
    </button>
  );
}

Si vous utilisez le Pages Router ou React avec votre propre backend, remplacez la Server Action par une route POST. Le reste de la structure ne change pas.

Le piège des variables d'environnement

Next.js détermine ce qui est envoyé au navigateur grâce à un préfixe. Il est facile d'ajouter ce préfixe par réflexe.

VariableDestination
WAJUB_SECRET_KEYServeur uniquement. Correct
NEXT_PUBLIC_WAJUB_SECRET_KEYIntégrée au bundle JavaScript. Ne faites jamais cela
NEXT_PUBLIC_WAJUB_PUBLIC_KEYCorrect, c'est précisément le rôle d'une clé publique

Si vous pensez qu'une clé a déjà été divulguée, révoquez-la depuis Settings › Developer › API Keys. Le renouvellement est immédiat et n'affecte pas vos autres clés.

Les différences réelles entre les modes

La partie serveur décrite plus haut est identique dans les trois modes. Seule la dernière ligne change : l'action du client sur la valeur reçue.

ModeRéponse de votre serveurAction du client
Redirectionauthorization_urlwindow.location.href = url
Intégréauthorization_tokenAffiche <CheckoutEmbed sessionId={...} /> avec ce jeton
Champs personnalisésauthorization_tokenAffiche <PaymentComponent /> et confirme avec useConfirmPayment

Commencez par la redirection. Wajub gère la liste des opérateurs, le texte de l'invite et chaque écran d'échec. Vous évitez ainsi de construire et maintenir une grande partie de l'interface.

Un jeton de session n'est pas une petite clé secrète

authorization_token sert uniquement à permettre au navigateur de terminer un paiement précis. Il ne peut ni lister, ni rembourser, ni lire quoi que ce soit d'autre. C'est précisément pourquoi vous pouvez l'envoyer à un client en toute sécurité. La page Sessions et sécurité définit cette frontière en détail.

Passez ensuite au code

Cette page s'arrête volontairement avant les détails internes des composants, car ils sont correctement documentés ailleurs, en un seul endroit.

Que pensez-vous de ce contenu ?