SumUp API : choisir l’autorisation entre OAuth 2.0 et clés API

Comparatif technique et opérationnel pour choisir entre OAuth 2.0 et clé API avec SumUp sur PrestaShop. Scénarios d’usage, patterns d’implémentation et checklist de production.

Diagramme illustrant le flux d'authentification avec OAuth 2.0 et une clé API.

Table des matières :

  1. Comprendre ce que SumUp expose : OAuth 2.0 vs “clé API” (et pourquoi ce n’est pas interchangeable)
  2. Quand OAuth 2.0 est le bon choix : multi-marchands, consentement, révocation, audit
  3. Quand une clé API est plus rationnelle : mono-compte, backend fermé, opérations batch
  4. Implémentation côté PrestaShop (8.1/8.2/9.x, PHP 8.2/8.3) : patterns qui évitent les erreurs classiques
  5. Grille de décision : choisir l’autorisation SumUp API sans se mentir sur l’exploitation
  6. Checklist de mise en production (valable OAuth 2.0 et clés API) : ce qui casse en vrai

Comprendre ce que SumUp expose : OAuth 2.0 vs “clé API” (et pourquoi ce n’est pas interchangeable)

SumUp API se consomme via HTTP(S) avec un jeton présenté comme un bearer token (typiquement dans l’en-tête Authorization: Bearer …). La différence entre OAuth 2.0 et une clé API n’est pas “un format de token” mais un modèle d’autorisation : qui accorde l’accès, à quel périmètre (scopes), comment on révoque/renouvelle, et surtout qui porte le risque en production (marchand, éditeur du module, agence, hébergeur).

« OAuth 2.0 is an authorization framework that enables a third-party application to obtain limited access to an HTTP service… » — IETF, RFC 6749 (OAuth 2.0)

Dans OAuth 2.0, vous avez (au minimum) un Authorization Server (SumUp), un Resource Server (les endpoints API), un Client (votre module / votre backend), et un Resource Owner (le marchand SumUp). L’accès se fait après un consentement explicite du marchand via un navigateur, avec des scopes (droits) et des tokens à durée limitée (souvent access_token + refresh_token). Techniquement, cela force votre intégration à gérer des redirections, un callback, des expirations et de la rotation.

À l’inverse, une “clé API” côté SumUp correspond en pratique à un secret statique (ou un token long-lived) qui authentifie votre compte marchand (ou une application interne) sans passer par une étape d’autorisation utilisateur interactive. C’est un choix valide uniquement quand vous ne cherchez pas à connecter plusieurs marchands, et que votre surface d’attaque est maîtrisée (stockage du secret, rotation, logs).

Sur PrestaShop, ce point est critique : par défaut, la couche Configuration enregistre des valeurs en base, et le cœur n’offre pas un gestionnaire de secrets robuste. Pour les fondamentaux (moindre privilège, rotation, limitation de débit), voyez aussi : Expertise PrestaShop — API : sécuriser API key, limiter le débit et renforcer la conformité

Pour clarifier “sans jargon”, une bonne manière de raisonner est de se poser deux questions simples :

  • Qui doit pouvoir couper l’accès facilement ?
    Avec OAuth, SumUp (et le marchand) ont des leviers standard (révocation, fin de session, rotation). Avec une clé API, vous êtes souvent dépendant d’une rotation manuelle.
  • Quel est le périmètre minimal acceptable ?
    OAuth est conçu pour un accès “borné” (scopes). Une clé API finit fréquemment par donner “trop” de permissions parce qu’on veut éviter les incidents liés aux droits.

Tableau de synthèse (pratique pour cadrer une décision en équipe) :

Critère OAuth 2.0 “Clé API” / token long-lived
Cible multi-marchands, module distribué mono-marchand, intégration interne
Consentement oui (flux navigateur) non
Granularité des droits scopes souvent global / peu granulaire
Rotation/révocation standardisées plus coûteuses, souvent manuelles
Complexité technique plus élevée plus faible
Impact d’une fuite réduit par expiration potentiellement élevé jusqu’à rotation

Enfin, côté contexte France/UE, n’oubliez pas que même si vous ne manipulez pas de données carte, vous traitez souvent des données de transaction (identifiants, montants, parfois emails/téléphones selon les flux). Cela implique des exigences opérationnelles “très concrètes” : minimisation des logs, contrôle d’accès au back-office, politique de rétention, et capacité à investiguer un incident sans exposer de secrets.

Quand OAuth 2.0 est le bon choix : multi-marchands, consentement, révocation, audit

OAuth 2.0 devient quasi obligatoire dès que votre intégration doit être réutilisable par des boutiques différentes (module distribué, SaaS, agence qui déploie chez plusieurs clients). Vous ne voulez pas recevoir/manipuler une clé SumUp “copiée-collée” par chaque marchand : vous voulez qu’il clique, s’authentifie chez SumUp, et que SumUp vous délivre un token borné par des scopes. C’est aussi le seul scénario qui tient quand votre produit doit passer un audit sécurité sérieux : vous pouvez prouver qui a autorisé quoi, et quand.

Mini-scénario typique (côté agence / éditeur) : vous publiez un module PrestaShop “SumUp Advanced” pour des marchands français et belges. Sans OAuth, votre support devient rapidement : “où est la clé ?”, “j’ai collé la mauvaise clé”, “j’ai régénéré la clé et plus rien ne marche”, “mon prestataire avait la clé et a quitté la société”. Avec OAuth, votre support bascule plutôt vers des sujets délimités : URL de callback, droits (scopes) insuffisants, accès révoqué. C’est rarement “agréable”, mais c’est plus standard et documentable.

En termes de cycle de vie, OAuth apporte deux mécanismes qui changent la donne : expiration de l’access_token (réduction de l’impact d’une fuite) et révocation (coupure propre). Même si SumUp vous fournit des tokens qui ressemblent à des clés API, la logique OAuth impose un contrôle côté provider. Pour les tokens “bearer”, le standard est clair :

« This specification describes how to use bearer tokens in HTTP requests to access OAuth 2.0 protected resources. » — IETF, RFC 6750 (Bearer Token Usage)

Côté implémentation, si votre flux implique un navigateur (back-office PrestaShop, onboarding marchand), vous devez privilégier Authorization Code (et éviter les flux hérités). Et si vous avez un “client public” (ex. front SPA, mobile), vous avez besoin de PKCE. Même dans un module PrestaShop classique (serveur), PKCE reste utile si vous ne pouvez pas garder un client_secret réellement secret (hébergement mutualisé, admins multiples, risques d’exfiltration).

« This extension describes a method for public clients to mitigate the threat of authorization code interception attacks. » — IETF, RFC 7636 (PKCE)

Deux points souvent sous-estimés (et qui font “exploser” des intégrations en production) :

  • Redirect URI strict : côté provider, la redirect_uri doit généralement matcher exactement ce qui est enregistré. En multi-boutique (ou multi-domaine), vous devez gérer les cas www, HTTPS, et les environnements (staging/prod) sans bricolage.
  • Scopes minimaux : demandez le minimum utile. C’est à la fois un point sécurité et un point “support” : moins de scopes = moins de risques d’erreurs et moins de surface lors d’un audit.

Quand une clé API est plus rationnelle : mono-compte, backend fermé, opérations batch

La clé API (ou token long-lived) est rationnelle quand vous êtes dans un cas mono-marchand : une seule boutique PrestaShop, un seul compte SumUp, et une intégration opérée par la même équipe (ou un prestataire) sur une infra contrôlée. Concrètement : vous déclenchez des paiements/transactions côté serveur, vous faites du reporting, ou vous réconciliez des opérations comptables. Vous n’avez pas besoin d’un écran d’autorisation, ni d’une gestion de refresh tokens, et vous voulez réduire la complexité opérationnelle.

Le vrai avantage n’est pas “moins de sécurité” mais moins d’états à gérer. OAuth vous force à gérer : tokens expirés, refresh qui échoue, consentement révoqué, scopes insuffisants, etc. Sur un checkout, ces cas provoquent des erreurs 401/403 au pire moment (panier), et votre module doit avoir une stratégie claire : retry contrôlé, bascule vers un autre moyen de paiement, journalisation et alerting. Une clé API simplifie le flux au prix d’un blast radius plus grand en cas de fuite.

Autre cas d’usage “raisonnable” : batch nocturne (ex. rapprochement des transactions, export comptable). Là, vous préférez souvent une authentification stable et une exécution robuste (avec reprises sur incident). Le point clé est de construire une vraie discipline autour du secret :

  • rotation planifiée (ex. trimestrielle) avant d’avoir un incident ;
  • procédure de révocation en urgence (qui fait quoi, en combien de temps) ;
  • séparation des environnements (clé différente pour staging vs prod).

Si vous partez sur une clé API, traitez-la comme un secret de prod (pas comme une “config”). Minimisez la diffusion : pas de logs, pas de stockage en clair dans la base, pas de commit, pas d’export automatique dans des dumps non chiffrés. Sur PrestaShop, c’est exactement le sujet “propre” : vous devez imposer vos règles parce que le cœur ne le fera pas à votre place. Pour un rappel des bonnes pratiques côté PHP (typage, exceptions, sécurité), lien utile : Expertise PrestaShop — PHP bonnes pratiques, sécurité et qualité de code

Implémentation côté PrestaShop (8.1/8.2/9.x, PHP 8.2/8.3) : patterns qui évitent les erreurs classiques

Sur PrestaShop 9.x (et plus largement 8.x), vous êtes dans un écosystème Symfony plus cohérent (services, contrôleurs, Twig). Si vous adaptez un module existant, anticipez les différences d’architecture et d’injection de dépendances (notamment la bascule progressive des contrôleurs legacy) : Expertise PrestaShop — adapter modules et thèmes à PrestaShop 9 et pour le cadrage PHP réellement supporté : Expertise PrestaShop — versions PHP recommandées pour PrestaShop 9

Deux “patterns” qui évitent beaucoup d’erreurs, quel que soit OAuth ou clé API :

  • Centraliser l’HTTP client (un seul service) : timeouts, headers, user-agent, retries, logs, corrélation… tout doit être cohérent, sinon vous allez déboguer des comportements divergents entre contrôleurs.
  • Centraliser l’obtention du jeton (un seul provider) : évitez le “je lis la config et je fais un if” dans 15 endroits. Le jour où vous changez la stratégie (rotation, chiffrement, refresh), vous ne voulez modifier qu’une brique.

OAuth 2.0 dans un module : callback, stockage, refresh

Le point non négociable : un endpoint de callback stable, HTTPS, et protégé contre le CSRF/relai d’attaque. En module, créez une route du type /module/votremodule/oauth/callback (contrôleur Symfony en PS9, ou ModuleFrontController en PS8) et validez systématiquement le paramètre state (et idéalement nonce si le provider le supporte). Le state doit être lié à la session back-office (ou à un identifiant d’admin) et expirer rapidement.

Ensuite, gérez deux secrets distincts :

  • client_secret (secret applicatif, identique pour toutes les boutiques si vous êtes éditeur d’un module) : à mettre hors base si possible (variable d’environnement / secret manager). Dans le monde réel, sur des mutualisés, c’est rarement “vraiment” secret.
  • refresh_token (secret par marchand/boutique) : à stocker par boutique (id_shop) et à chiffrer.

PrestaShop ne fournit pas un vault. La stratégie robuste est : chiffrement applicatif (libsodium/openssl) avec une clé maître hors base (ENV, Docker secret, ou fichier protégé au niveau OS). Si vous stockez en ps_configuration, assumez que toute personne avec un accès SQL ou un dump a potentiellement le token.

Exemple minimaliste (illustratif) de séparation “chiffrement applicatif” + stockage en base — à adapter à votre gestion des erreurs et à votre modèle multi-boutique :

<?php
// Exemple illustratif (pas un copier-coller prod tel quel)
final class SecretBox
{
    public function __construct(private string $masterKeyB64) {}

    public function encrypt(string $plain): string
    {
        $key = sodium_base642bin($this->masterKeyB64, SODIUM_BASE64_VARIANT_ORIGINAL);
        $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $cipher = sodium_crypto_secretbox($plain, $nonce, $key);

        return base64_encode($nonce.$cipher);
    }

    public function decrypt(string $payloadB64): string
    {
        $key = sodium_base642bin($this->masterKeyB64, SODIUM_BASE64_VARIANT_ORIGINAL);
        $raw = base64_decode($payloadB64, true);
        if ($raw === false || strlen($raw) < SODIUM_CRYPTO_SECRETBOX_NONCEBYTES) {
            throw new RuntimeException('Secret invalide');
        }
        $nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

        $plain = sodium_crypto_secretbox_open($cipher, $nonce, $key);
        if ($plain === false) {
            throw new RuntimeException('Déchiffrement impossible');
        }
        return $plain;
    }
}

Enfin, implémentez le refresh de manière déterministe : un service SumUpTokenProvider qui retourne toujours un access_token valide, et rafraîchit si expires_at - skew < now. Le “skew” (par ex. 60 secondes) évite les erreurs de bord. Ajoutez un verrou (mutex Redis, MySQL advisory lock) pour éviter 20 refresh concurrents lors d’un pic de trafic.

Pseudo-logique utile (pour cadrer la méthode) :

  • si access_token encore valide → retourner ;
  • sinon tenter refresh une seule fois (avec verrou) ;
  • si refresh échoue → invalider localement et remonter une erreur actionnable (alerte + message BO), plutôt que “boucler” et saturer l’API.

Si vous avez déjà Redis en place pour PrestaShop, vous pouvez vous aligner sur les patterns de cache/locking : Expertise PrestaShop — Redis pour PrestaShop

Clé API : injection stricte et surface minimale

Avec une clé API, votre priorité est la non-exposition : aucune manipulation côté front, aucune config visible en clair dans le BO, et une séparation claire entre le code qui lit le secret et les contrôleurs.

En pratique : un champ BO qui accepte la clé, mais qui n’affiche jamais la valeur complète (masquage, ex. ••••••••••1234), et une validation stricte (longueur, alphabet autorisé) sans jamais logger l’input. Attention également à l’“effet de bord” fréquent en support : certains marchands copient-collent une clé avec un espace de fin ou un retour ligne. Un trim() contrôlé côté backend évite des heures de debug.

Dans vos appels HTTP, construisez un client centralisé et tracez uniquement des métadonnées : status code, endpoint, latence, identifiant de corrélation, mais jamais les headers d’auth. Concrètement, si vous faites du debug, logguez :

  • la route logique (ex. POST /payments) mais pas l’URL complète si elle contient des IDs sensibles ;
  • un request_id interne ;
  • le temps total ;
  • le code HTTP et, éventuellement, un code erreur “fonctionnel” si l’API en retourne (sans payload brut).

Si vous avez un reverse proxy (HAProxy/Nginx), ajoutez des règles de rate limiting et de détection d’anomalies (ex. rafales de 401/403). Le pattern “mettre un garde-fou réseau” est souvent plus efficace que d’espérer que l’app ne se trompe jamais : Expertise PrestaShop — HAProxy, rate limiting et supervision

Webhooks, idempotence et gestion d’erreurs : le vrai sujet, quel que soit le mode d’auth

OAuth ou clé API ne résout pas les problèmes de paiements distribués : vous devez traiter les webhooks comme une source d’état (échec/succès asynchrone), et rendre vos endpoints idempotents. Stockez un event_id (ou équivalent) et refusez les doublons. Côté PrestaShop, journalisez dans une table dédiée module (pas dans ps_log uniquement), avec index sur l’identifiant d’événement et sur l’ID commande.

Bon réflexe opérationnel : lors d’un paiement, votre boutique peut avoir un “temps long” (SCA / validation, latence fournisseur, réseau mobile). En Europe (dont France), ce type de flux asynchrone est courant : vous devez donc éviter de “conclure” trop tôt côté checkout si l’état final dépend d’un retour serveur. Les webhooks sont généralement ce qui permet de réconcilier l’état en cas de rupture (navigateur fermé, retour sur le site non exécuté, etc.).

Idempotence côté webhook (pattern simple) :

  • début de traitement : INSERT event_id avec contrainte unique ;
  • si violation de contrainte → webhook déjà traité → répondre 200/204 sans retraiter ;
  • sinon traiter, puis marquer “done”.

Et si SumUp (ou votre provider) fournit une signature de webhook (HMAC, secret partagé, clé publique), vérifiez-la systématiquement : c’est ce qui empêche qu’un attaquant “pousse” de faux événements vers votre endpoint.

Pour les erreurs, ne faites pas de “retry aveugle”. Distinguez :

  • 429 (backoff exponentiel),
  • 401 (token invalide → refresh ou alerte),
  • 403 (scope/droits → action humaine),
  • 5xx (retry borné).

Pour rendre ça actionnable, fixez quelques règles de base (souvent suffisantes) :

  • timeouts HTTP : connect ~2s, réponse ~10s (à ajuster selon vos contraintes) ;
  • retries : 0 en checkout (ou 1 max, très contrôlé), 2–3 sur des batchs non interactifs ;
  • backoff : exponentiel + jitter (pour éviter que tous vos workers réessaient en même temps).

Et mettez des alertes sur les métriques : taux de 401, taux de 5xx, latence P95. Si vous n’avez pas déjà de stratégie de monitoring côté boutique, alignez-vous sur une approche logs+alertes exploitable : Expertise PrestaShop — monitoring et alertes et, côté infra, une supervision plus large : Expertise PrestaShop — Netdata et supervision infra

Grille de décision : choisir l’autorisation SumUp API sans se mentir sur l’exploitation

Premier critère : nombre de marchands. Si vous développez un module installé sur 50 boutiques différentes, la clé API devient un anti-pattern : vous allez manipuler des secrets humains (copier-coller), gérer du support, et subir des fuites. OAuth 2.0 est fait pour ça : consentement, scopes, révocation. Si vous êtes en mono-boutique (un seul marchand), la clé API est plus simple et souvent plus robuste en production.

Deuxième critère : modèle de menaces et responsabilités. Avec OAuth, vous stockez des refresh tokens (toujours sensibles), mais l’access_token a une durée de vie courte, et SumUp peut couper proprement. Avec une clé API, la fuite est souvent catastrophique jusqu’à rotation, et la rotation elle-même est un chantier (coordination, downtime, propagation des secrets). C’est exactement le type de dette qui explose “le jour où” (dump base récupéré, log debug mal filtré, accès admin compromis). Si vous avez déjà une démarche de durcissement (WAF, anti-faux positifs checkout), vous êtes déjà dans le bon état d’esprit : Expertise PrestaShop — WAF pour PrestaShop

Troisième critère : UX et support. OAuth impose une UX d’onboarding (bouton “Connecter SumUp”, redirection, permissions) et donc du support (callback URL, erreurs de consentement, comptes mal configurés). Une clé API impose une UX d’administration (coller une clé) et surtout du support sécurité (rotation, “où est ma clé”, “je l’ai perdue”). En agence, les deux coûts existent ; celui d’OAuth est plus “produit”, celui des clés est plus “incident”.

Pour rendre la décision plus tranchée, voici une grille “oui/non” rapide :

  • Votre module est-il installé chez des tiers (Marketplace, distribution) ? → OAuth recommandé.
  • Avez-vous besoin que le marchand puisse révoquer l’accès sans vous contacter ? → OAuth.
  • Êtes-vous dans un contexte “run” mature (secrets manager, rotation, monitoring, accès restreints) ? → clé API envisageable.
  • Avez-vous des environnements multiples et du multi-domaine difficile (staging/prod, multi-shop) ? → la clé API peut réduire la complexité si mono-marchand.
  • Avez-vous une obligation d’audit / traçabilité fine des consentements ? → OAuth.

Checklist de mise en production (valable OAuth 2.0 et clés API) : ce qui casse en vrai

Commencez par verrouiller le stockage. Si vous ne pouvez pas utiliser un secret manager, au minimum : chiffrez au repos, séparez la clé de chiffrement de la base, et interdisez l’export de configuration contenant des secrets en clair. Sur des environnements conteneurisés, utilisez des variables d’environnement injectées au runtime (Kubernetes Secrets, Docker secrets) plutôt qu’un champ BO pour les secrets applicatifs. Et ne mélangez pas “config fonctionnelle” et “secret”.

Checklist (copiable telle quelle dans un ticket de mise en prod) :

  • [ ] Secrets jamais loggués (headers Authorization, payloads sensibles, tokens, refresh tokens)
  • [ ] Stockage chiffré des tokens (et clé maître hors base)
  • [ ] Rotation documentée (qui / comment / délai) + testée sur staging
  • [ ] Timeouts HTTP définis (connect & read) + gestion d’erreurs par code HTTP
  • [ ] Retries bornés (pas de boucle infinie), backoff sur 429
  • [ ] Webhooks idempotents (contrainte unique sur event_id) + vérification d’authenticité si fournie
  • [ ] Corrélation (un identifiant par paiement) + table de logs module indexée
  • [ ] Alerting sur pics de 401, 403, 429, 5xx et latence P95
  • [ ] Accès BO restreints (principe du moindre privilège), et hygiène des exports/dumps

Ensuite, imposez des garde-fous réseau et applicatifs : TLS strict, timeouts HTTP courts (connect/read), retries bornés, et rate limiting. Si vous avez déjà une API gateway ou une architecture multi-services, centralisez l’auth, le throttling et les quotas : Expertise PrestaShop — API Gateway et rate limiting (même si votre boutique est monolithique, les patterns restent valables). À l’échelle serveur, un reverse proxy capable de limiter et d’observer (HAProxy) est une brique pragmatique.

Enfin, traitez l’observabilité comme une fonctionnalité. Logguez un identifiant de corrélation par paiement, stockez les payloads sensibles de manière minimale (masquage), et exposez des métriques : nombre d’appels SumUp/min, taux de succès, P95/P99, distribution des codes HTTP, et temps de réponse. Ajoutez des alertes sur : pics de 401 (token expiré/invalid), pics de 403 (scopes), pics de 429 (quota), et 5xx (incident provider). Ce n’est pas “nice to have” : c’est ce qui évite de déboguer à l’aveugle un checkout qui ne répond plus (voir aussi la méthodologie côté erreurs serveur : Expertise PrestaShop — diagnostic erreurs serveur).

Références externes utiles (docs et standards)


À lire aussi