<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Authentication on kenji.blog</title><link>http://kenji.blog/fr/tags/authentication/</link><description>Recent content in Authentication on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 12:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/authentication/index.xml" rel="self" type="application/rss+xml"/><item><title>Explication de l'architecture OAuth 2.0 : Apprendre à travers l'intégration d'une application Slack</title><link>http://kenji.blog/fr/p/oauth2-architecture-slack-app-integration/</link><pubDate>Sun, 13 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/oauth2-architecture-slack-app-integration/</guid><description>&lt;img src="http://kenji.blog/p/oauth2-architecture-slack-app-integration/img/eyecatch.jpg" alt="Featured image of post Explication de l'architecture OAuth 2.0 : Apprendre à travers l'intégration d'une application Slack" />&lt;h1 id="introduction--pourquoi-apprendre-oauth-20-">Introduction : Pourquoi apprendre OAuth 2.0 ?
&lt;/h1>&lt;p>Dans les applications Web modernes, il est devenu courant que plusieurs services collaborent ensemble. Par exemple, des fonctionnalités telles que &amp;ldquo;Se connecter avec un compte Google&amp;rdquo;, &amp;ldquo;Envoyer une notification à Slack lorsqu&amp;rsquo;une tâche Trello est mise à jour&amp;rdquo; ou &amp;ldquo;Ajouter automatiquement un lien de réunion Zoom à Google Agenda&amp;rdquo;. Dans les coulisses de toutes ces actions se trouve le framework d&amp;rsquo;autorisation appelé &lt;strong>OAuth 2.0 (Open Authorization 2.0)&lt;/strong>.&lt;/p>
&lt;p>Auparavant, lors de l&amp;rsquo;échange de données entre différents services, des méthodes extrêmement dangereuses appelées &amp;ldquo;authentification de base&amp;rdquo; et &amp;ldquo;partage de mot de passe&amp;rdquo; étaient utilisées, où l&amp;rsquo;utilisateur donnait directement son identifiant et son mot de passe au service partenaire. Cependant, avec cette méthode, le service partenaire détient tous les droits de l&amp;rsquo;utilisateur, ce qui entraîne des risques de sécurité critiques.&lt;/p>
&lt;p>OAuth 2.0 a été créé en tant que protocole standard (RFC 6749) pour éviter un tel &amp;ldquo;partage de mot de passe&amp;rdquo; tout en déléguant à des applications tierces &amp;ldquo;uniquement des autorisations spécifiques (portées)&amp;rdquo; pour &amp;ldquo;une durée limitée&amp;rdquo;.&lt;/p>
&lt;p>Dans cet article, nous expliquerons le fonctionnement d&amp;rsquo;OAuth 2.0 de manière extrêmement détaillée et pratique à travers la mise en œuvre d&amp;rsquo;une application (Slack App) pour &lt;strong>Slack (Slack API)&lt;/strong>, qui est devenu la norme de facto en tant qu&amp;rsquo;outil de communication d&amp;rsquo;entreprise. Il s&amp;rsquo;agit d&amp;rsquo;un guide définitif de plus de 10 000 caractères couvrant des exemples de code utilisant Node.js (Express), des diagrammes de séquence illustrant le flux du protocole, et plongeant dans les contextes mathématiques et cryptographiques de paramètres importants pour la sécurité comme &lt;code>state&lt;/code> et PKCE.&lt;/p>
&lt;hr>
&lt;h1 id="1-concept-de-base-doauth-20--les-4-rôles-roles">1. Concept de base d&amp;rsquo;OAuth 2.0 : Les 4 rôles (Roles)
&lt;/h1>&lt;p>La première étape pour comprendre OAuth 2.0 est d&amp;rsquo;identifier précisément les acteurs (Rôles). Le RFC 6749 définit les 4 rôles suivants.&lt;/p>
&lt;pre class="mermaid">
graph TD
RO[&amp;#34;Resource Owner (Utilisateur)&amp;#34;] -- &amp;#34;Accorde l&amp;#39;autorisation&amp;#34; --&amp;gt; C[&amp;#34;Client (Slack App)&amp;#34;]
C -- &amp;#34;Demande l&amp;#39;autorisation&amp;#34; --&amp;gt; AS[&amp;#34;Authorization Server (Serveur d&amp;#39;autorisation Slack)&amp;#34;]
AS -- &amp;#34;Émet un jeton d&amp;#39;accès&amp;#34; --&amp;gt; C
C -- &amp;#34;Accède avec le jeton&amp;#34; --&amp;gt; RS[&amp;#34;Resource Server (Serveur API Slack)&amp;#34;]
RO -- &amp;#34;Se connecte avec ID/Mot de passe&amp;#34; --&amp;gt; AS
&lt;/pre>
&lt;ol>
&lt;li>&lt;strong>Resource Owner (Propriétaire de la ressource)&lt;/strong>
&lt;ul>
&lt;li>Il s&amp;rsquo;agit de l&amp;rsquo;entité ayant le pouvoir d&amp;rsquo;accorder l&amp;rsquo;accès à une ressource. Il désigne généralement l&amp;rsquo;&amp;ldquo;utilisateur final (humain)&amp;rdquo;. Dans notre exemple, c&amp;rsquo;est &amp;ldquo;vous-même, appartenant à un espace de travail Slack et ayant la permission de publier des messages dans des canaux&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Client (Client)&lt;/strong>
&lt;ul>
&lt;li>C&amp;rsquo;est l&amp;rsquo;application qui tente d&amp;rsquo;accéder au serveur de ressources avec l&amp;rsquo;autorisation du propriétaire de la ressource. Dans notre exemple, c&amp;rsquo;est &amp;ldquo;l&amp;rsquo;application Node.js que vous développez (Slack App)&amp;rdquo;. Bien qu&amp;rsquo;il soit appelé &amp;ldquo;Client&amp;rdquo;, même s&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;une application Web s&amp;rsquo;exécutant côté serveur, il est appelé &amp;ldquo;Client&amp;rdquo; dans le contexte d&amp;rsquo;OAuth.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Authorization Server (Serveur d&amp;rsquo;autorisation)&lt;/strong>
&lt;ul>
&lt;li>C&amp;rsquo;est le serveur qui authentifie le propriétaire de la ressource, obtient son autorisation, puis émet un jeton d&amp;rsquo;accès (access token) au client. Dans notre exemple, c&amp;rsquo;est l&amp;rsquo;infrastructure d&amp;rsquo;authentification de Slack qui fournit &lt;code>slack.com/oauth/v2/authorize&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Resource Server (Serveur de ressources)&lt;/strong>
&lt;ul>
&lt;li>C&amp;rsquo;est le serveur qui héberge les ressources protégées, accepte les demandes d&amp;rsquo;accès aux ressources à l&amp;rsquo;aide de jetons d&amp;rsquo;accès et y répond. Dans notre exemple, ce sont les points de terminaison &lt;code>slack.com/api/&lt;/code> qui fournissent des API comme &lt;code>chat.postMessage&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Le flux OAuth, en un mot, est la série d&amp;rsquo;étapes où &lt;strong>&amp;ldquo;le Client, avec le consentement du Propriétaire de la ressource, reçoit un jeton d&amp;rsquo;accès du Serveur d&amp;rsquo;autorisation et l&amp;rsquo;utilise pour récupérer ou manipuler des données du Serveur de ressources&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="2-anatomie-complète-de-loctroi-de-code-dautorisation-authorization-code-grant">2. Anatomie complète de l&amp;rsquo;octroi de code d&amp;rsquo;autorisation (Authorization Code Grant)
&lt;/h1>&lt;p>Bien qu&amp;rsquo;il existe plusieurs flux (types d&amp;rsquo;octroi) dans OAuth 2.0, l&amp;rsquo;&lt;strong>octroi de code d&amp;rsquo;autorisation (Authorization Code Grant)&lt;/strong> est le plus recommandé et le plus largement utilisé dans les environnements où un secret client (Client Secret) peut être conservé en toute sécurité côté serveur, comme les applications Web.&lt;/p>
&lt;p>La plus grande caractéristique de l&amp;rsquo;octroi de code d&amp;rsquo;autorisation est qu&amp;rsquo;il sépare clairement le &lt;strong>canal frontal (communication via le navigateur)&lt;/strong> du &lt;strong>canal arrière (communication directe entre serveurs)&lt;/strong>. Dans le canal frontal, seul un &amp;ldquo;code d&amp;rsquo;autorisation (Authorization Code)&amp;rdquo; temporaire est transmis, et l&amp;rsquo;obtention finale du &amp;ldquo;jeton d&amp;rsquo;accès&amp;rdquo; est effectuée dans le canal arrière, ce qui réduit considérablement le risque que le jeton soit divulgué dans l&amp;rsquo;historique du navigateur ou le référent.&lt;/p>
&lt;p>Le diagramme de séquence ci-dessous montre l&amp;rsquo;ensemble du processus de l&amp;rsquo;octroi de code d&amp;rsquo;autorisation dans une Slack App.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
autonumber
participant U as &amp;#34;Resource Owner (Navigateur Web)&amp;#34;
participant C as &amp;#34;Client (App Node.js)&amp;#34;
participant AS as &amp;#34;Authorization Server (Authentification Slack)&amp;#34;
participant RS as &amp;#34;Resource Server (API Slack)&amp;#34;
U-&amp;gt;&amp;gt;C: &amp;#34;Clique sur le bouton d&amp;#39;installation de l&amp;#39;application (GET /slack/install)&amp;#34;
Note over C: &amp;#34;Génération du paramètre state&amp;#34;
C--&amp;gt;&amp;gt;U: &amp;#34;Redirection : 302 Found (Location: URL d&amp;#39;authentification Slack)&amp;#34;
U-&amp;gt;&amp;gt;AS: &amp;#34;GET /oauth/v2/authorize?client_id=...&amp;amp;scope=...&amp;amp;state=...&amp;#34;
AS--&amp;gt;&amp;gt;U: &amp;#34;Écran de connexion Slack et écran d&amp;#39;approbation des autorisations (Consent Screen)&amp;#34;
U-&amp;gt;&amp;gt;AS: &amp;#34;Autoriser les permissions (Allow)&amp;#34;
Note over AS: &amp;#34;Génération du code d&amp;#39;autorisation (code)&amp;#34;
AS--&amp;gt;&amp;gt;U: &amp;#34;Redirection : 302 Found (Location: URL de rappel du client?code=...&amp;amp;state=...)&amp;#34;
U-&amp;gt;&amp;gt;C: &amp;#34;GET /slack/oauth_redirect?code=...&amp;amp;state=...&amp;#34;
Note over C: &amp;#34;Vérification du paramètre state (Protection CSRF)&amp;#34;
C-&amp;gt;&amp;gt;AS: &amp;#34;POST /api/oauth.v2.access (code, client_id, client_secret)&amp;#34;
Note over C,AS: &amp;#34;Communication par canal arrière (Sans passer par le navigateur)&amp;#34;
AS--&amp;gt;&amp;gt;C: &amp;#34;200 OK (JSON : Émission de access_token etc.)&amp;#34;
C-&amp;gt;&amp;gt;RS: &amp;#34;POST /api/chat.postMessage (Authorization: Bearer &amp;lt;access_token&amp;gt;)&amp;#34;
RS--&amp;gt;&amp;gt;C: &amp;#34;200 OK (Message publié avec succès)&amp;#34;
&lt;/pre>
&lt;p>Démêlons ce flux un par un à travers l&amp;rsquo;implémentation concrète de code Node.js (Express).&lt;/p>
&lt;hr>
&lt;h1 id="3-préparation-à-limplémentation--configuration-dans-la-slack-developer-console">3. Préparation à l&amp;rsquo;implémentation : Configuration dans la Slack Developer Console
&lt;/h1>&lt;p>Avant d&amp;rsquo;écrire du code, nous devons enregistrer &amp;ldquo;l&amp;rsquo;existence d&amp;rsquo;un nouveau client&amp;rdquo; dans le système de Slack.&lt;/p>
&lt;ol>
&lt;li>Accédez à &lt;a class="link" href="https://api.slack.com/apps" target="_blank" rel="noopener"
>Slack API: Applications&lt;/a> et cliquez sur &amp;ldquo;Create New App&amp;rdquo;.&lt;/li>
&lt;li>Sélectionnez &amp;ldquo;From scratch&amp;rdquo;, spécifiez le nom de l&amp;rsquo;application (par exemple : &lt;code>My First OAuth App&lt;/code>) et l&amp;rsquo;espace de travail d&amp;rsquo;installation.&lt;/li>
&lt;li>Sur l&amp;rsquo;écran &amp;ldquo;Basic Information&amp;rdquo; après la création, obtenez les 2 informations d&amp;rsquo;identification importantes suivantes.
&lt;ul>
&lt;li>&lt;strong>Client ID&lt;/strong> : Un ID qui identifie publiquement et de manière unique votre application. Il n&amp;rsquo;y a aucun problème à l&amp;rsquo;inclure dans les requêtes passant par le navigateur (canal frontal).&lt;/li>
&lt;li>&lt;strong>Client Secret&lt;/strong> : Une chaîne secrète que seule votre application connaît. &lt;strong>Ne l&amp;rsquo;exposez absolument jamais côté navigateur, et ne la validez (commit) pas sur GitHub, etc.&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Accédez à l&amp;rsquo;écran &amp;ldquo;OAuth &amp;amp; Permissions&amp;rdquo; et enregistrez l&amp;rsquo;URL de rappel (callback) dans &amp;ldquo;Redirect URLs&amp;rdquo;. Cette fois, en supposant un développement local, nous configurons ce qui suit.
&lt;ul>
&lt;li>&lt;code>http://localhost:3000/slack/oauth_redirect&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>La préparation est maintenant terminée. Passons à l&amp;rsquo;implémentation du serveur.&lt;/p>
&lt;hr>
&lt;h1 id="4-étape-dimplémentation-1--slackinstall-et-le-paramètre-state-pour-contrer-le-csrf">4. Étape d&amp;rsquo;implémentation 1 : &lt;code>/slack/install&lt;/code> et le paramètre &lt;code>state&lt;/code> pour contrer le CSRF
&lt;/h1>&lt;p>Créons le premier point de terminaison pour que les utilisateurs commencent à utiliser l&amp;rsquo;application (l&amp;rsquo;installer dans l&amp;rsquo;espace de travail). La plus grande responsabilité ici est de rediriger l&amp;rsquo;utilisateur vers le serveur d&amp;rsquo;autorisation de Slack, mais la &lt;strong>génération et la sauvegarde du paramètre &lt;code>state&lt;/code>&lt;/strong> sont extrêmement importantes pour la sécurité.&lt;/p>
&lt;h2 id="nécessité-du-paramètre-state-prévention-des-attaques-csrf">Nécessité du paramètre state (Prévention des attaques CSRF)
&lt;/h2>&lt;p>S&amp;rsquo;il n&amp;rsquo;y a pas de paramètre &lt;code>state&lt;/code>, un attaquant malveillant peut lancer le processus d&amp;rsquo;autorisation avec son propre compte Slack et faire en sorte que la victime clique sur une URL de rappel (par exemple : &lt;code>http://localhost:3000/slack/oauth_redirect?code=ATTACKER_CODE&lt;/code>) contenant le &amp;ldquo;code d&amp;rsquo;autorisation&amp;rdquo; obtenu. Lorsque le navigateur de la victime exécute cela, l&amp;rsquo;association avec le compte Slack de l&amp;rsquo;attaquant est complétée dans la session de la victime, ce qui entraîne des fuites d&amp;rsquo;informations ou des opérations involontaires (Login CSRF).&lt;/p>
&lt;p>Pour éviter cela, &lt;code>state&lt;/code> est une chaîne aléatoire imprévisible permettant de vérifier que le navigateur qui a initié la requête et le navigateur qui a reçu le rappel sont les mêmes.&lt;/p>
&lt;h2 id="entropie-de-state-contexte-mathématique">Entropie de state (Contexte mathématique)
&lt;/h2>&lt;p>Afin de générer un &lt;code>state&lt;/code> sécurisé, un nombre aléatoire avec une &amp;ldquo;entropie (quantité d&amp;rsquo;information)&amp;rdquo; suffisante est nécessaire. L&amp;rsquo;entropie $E$ dépend du nombre de types de chaînes générées $N$, et est exprimée par la formule suivante.&lt;/p>
$$
E = \log_2(N) \quad (\text{unité : bits})
$$&lt;p>Par exemple, si nous générons un nombre pseudo-aléatoire cryptographiquement sécurisé (CSPRNG) de 16 octets et le convertissons en une chaîne hexadécimale (Hex), le nombre d&amp;rsquo;états qui peuvent être représentés est de $2^{128}$.&lt;/p>
$$
E = \log_2(2^{128}) = 128 \text{ bits}
$$&lt;p>Avec 128 bits d&amp;rsquo;entropie, il est pratiquement impossible (probabilité astronomique) de trouver une collision par attaque par force brute dans l&amp;rsquo;informatique moderne. Généralement, un &lt;code>state&lt;/code> avec au moins 128 bits d&amp;rsquo;entropie est recommandé comme exigence de sécurité.&lt;/p>
&lt;h2 id="implémentation-avec-nodejs">Implémentation avec Node.js
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// app.js (Extrait)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">express&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;express&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">crypto&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;crypto&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;express-session&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">dotenv&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;dotenv&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dotenv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">config&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">express&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Configuration du middleware de session (pour sauvegarder state)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">use&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">session&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">secret&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SESSION_SECRET&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">resave&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">saveUninitialized&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cookie&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">secure&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">false&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// Mettre à true en environnement de production
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">SLACK_CLIENT_ID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SLACK_CLIENT_ID&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">SLACK_AUTHORIZE_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://slack.com/oauth/v2/authorize&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/slack/install&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">req&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Génère un nombre aléatoire fort de 16 octets et le convertit en chaîne hexadécimale (Entropie : 128 bits)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">crypto&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">randomBytes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">toString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;hex&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Sauvegarde dans la session pour pouvoir le vérifier lors du rappel
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">req&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">oauth_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">state&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Liste des portées (permissions) demandées (séparées par des virgules)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// chat:write = Permission d&amp;#39;envoyer un message dans un canal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// channels:read = Permission de lire les informations des canaux publics
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">scope&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;chat:write,channels:read&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Paramètres d&amp;#39;URL pour construire le serveur d&amp;#39;autorisation de Slack
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">URLSearchParams&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">client_id&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">SLACK_CLIENT_ID&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">scope&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">scope&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">state&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">state&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">redirect_uri&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;http://localhost:3000/slack/oauth_redirect&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">authUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sb">`&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">SLACK_AUTHORIZE_URL&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">?&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">toString&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Redirige l&amp;#39;utilisateur vers l&amp;#39;écran d&amp;#39;autorisation de Slack (302 Found)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">redirect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">authUrl&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lorsque vous accédez à ce point de terminaison, la réponse HTTP ressemblera à ceci.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-http" data-lang="http">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">HTTP&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="m">1.1&lt;/span> &lt;span class="m">302&lt;/span> &lt;span class="ne">Found&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Location&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="l">https://slack.com/oauth/v2/authorize?client_id=123.456&amp;amp;scope=chat%3Awrite%2Cchannels%3Aread&amp;amp;state=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6&amp;amp;redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fslack%2Foauth_redirect&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Set-Cookie&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="l">connect.sid=...; Path=/; HttpOnly&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Le navigateur de l&amp;rsquo;utilisateur naviguera immédiatement vers l&amp;rsquo;emplacement &lt;code>Location&lt;/code> spécifié, l&amp;rsquo;écran de Slack (Consent Screen) s&amp;rsquo;affichera, et l&amp;rsquo;écran familier &amp;ldquo;My First OAuth App demande l&amp;rsquo;accès à votre espace de travail&amp;rdquo; apparaîtra.&lt;/p>
&lt;hr>
&lt;h1 id="5-étape-dimplémentation-2--réception-du-rappel-et-échange-du-jeton-daccès">5. Étape d&amp;rsquo;implémentation 2 : Réception du rappel et échange du jeton d&amp;rsquo;accès
&lt;/h1>&lt;p>Lorsque l&amp;rsquo;utilisateur clique sur &amp;ldquo;Autoriser (Allow)&amp;rdquo; sur l&amp;rsquo;écran de Slack, le serveur de Slack redirige le navigateur de l&amp;rsquo;utilisateur vers la &lt;code>redirect_uri&lt;/code> que nous avons configurée. À ce moment-là, le &lt;code>code&lt;/code> (code d&amp;rsquo;autorisation) et le &lt;code>state&lt;/code> que nous avons envoyés précédemment sont joints en tant que paramètres de requête de l&amp;rsquo;URL.&lt;/p>
&lt;p>Le backend effectue les opérations suivantes :&lt;/p>
&lt;ol>
&lt;li>Vérifier si le &lt;code>state&lt;/code> envoyé correspond exactement au &lt;code>state&lt;/code> sauvegardé dans la session.&lt;/li>
&lt;li>Si ça correspond, utiliser le &lt;code>code&lt;/code> reçu, son propre &lt;code>client_id&lt;/code> et l&amp;rsquo;information secrète &lt;code>client_secret&lt;/code> pour communiquer avec l&amp;rsquo;API Slack via le canal arrière et demander un jeton d&amp;rsquo;accès.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">axios&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;axios&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">SLACK_CLIENT_SECRET&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SLACK_CLIENT_SECRET&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">SLACK_ACCESS_TOKEN_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://slack.com/api/oauth.v2.access&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/slack/oauth_redirect&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kr">async&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">req&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">code&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">state&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">error&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">req&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">query&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Gestion du cas où l&amp;#39;utilisateur refuse l&amp;#39;autorisation
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">error&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;access_denied&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">403&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;L\&amp;#39;accès a été refusé.&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Vérification du state (Protection CSRF)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">savedState&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">req&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">oauth_state&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="nx">state&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="nx">state&lt;/span> &lt;span class="o">!==&lt;/span> &lt;span class="nx">savedState&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">400&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Paramètre State Invalide (Attaque CSRF Détectée)&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Supprimer le state utilisé (Prévention des attaques par rejeu)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">delete&lt;/span> &lt;span class="nx">req&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">oauth_state&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. Échanger le code d&amp;#39;autorisation contre un jeton d&amp;#39;accès (Communication par canal arrière)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">tokenResponse&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">axios&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">SLACK_ACCESS_TOKEN_URL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">URLSearchParams&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">client_id&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">SLACK_CLIENT_ID&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">client_secret&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">SLACK_CLIENT_SECRET&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">code&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">code&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">redirect_uri&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;http://localhost:3000/slack/oauth_redirect&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}).&lt;/span>&lt;span class="nx">toString&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">headers&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Content-Type&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;application/x-www-form-urlencoded&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">tokenResponse&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">data&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ok&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Erreur d\&amp;#39;échange de jeton :&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Erreur de l&amp;#39;API Slack : &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Succès ! Obtention du jeton d&amp;#39;accès
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">accessToken&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">access_token&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">teamName&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">team&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">botUserId&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">bot_user_id&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Installé avec succès sur &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">teamName&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">. Jeton d&amp;#39;accès : &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">accessToken&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Normalement, ici, nous le crypterions et le sauvegarderions dans la base de données
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// saveToDatabase(data.team.id, encrypt(accessToken));
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`L&amp;#39;installation est terminée ! Espace de travail : &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">teamName&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">err&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Erreur réseau :&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Une erreur de communication est survenue.&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En réponse à cette requête &lt;code>/api/oauth.v2.access&lt;/code>, Slack renverra un JSON comme celui-ci.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ok&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;app_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;A12345678&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;authed_user&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;U12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;scope&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;chat:write,channels:read&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;token_type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;bot&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;access_token&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YOUR_BOT_TOKEN_HERE&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;bot_user_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;B12345678&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;team&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;T12345678&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;My Workspace&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;enterprise&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cette chaîne commençant par &lt;code>xoxb-&lt;/code> est le &lt;strong>Bot Access Token (Jeton d&amp;rsquo;accès de Bot)&lt;/strong> dans Slack. Désormais, lorsque l&amp;rsquo;application envoie une requête à l&amp;rsquo;API Slack (Resource Server), elle joindra &lt;code>Authorization: Bearer xoxb-...&lt;/code> dans l&amp;rsquo;en-tête HTTP pour prouver l&amp;rsquo;authentification et l&amp;rsquo;autorisation.&lt;/p>
&lt;hr>
&lt;h1 id="6-portées-de-jeton-et-principe-du-moindre-privilège-principle-of-least-privilege">6. Portées de jeton et principe du moindre privilège (Principle of Least Privilege)
&lt;/h1>&lt;p>L&amp;rsquo;un des concepts les plus importants d&amp;rsquo;OAuth 2.0 est la &amp;ldquo;Portée (Scope)&amp;rdquo;. La portée désigne la plage d&amp;rsquo;autorisations associée à un jeton d&amp;rsquo;accès.&lt;/p>
&lt;p>Dans Slack, les autorisations sont classées très finement et se divisent principalement en &lt;strong>Bot Token Scopes&lt;/strong> et &lt;strong>User Token Scopes&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;code>chat:write&lt;/code> (Bot) : Permission pour l&amp;rsquo;application (le bot) de publier un message dans un canal en son propre nom.&lt;/li>
&lt;li>&lt;code>chat:write&lt;/code> (User) : Permission de publier un message au nom de l&amp;rsquo;utilisateur qui a installé l&amp;rsquo;application (avec le nom et l&amp;rsquo;icône de l&amp;rsquo;utilisateur).&lt;/li>
&lt;li>&lt;code>channels:read&lt;/code> : Permission d&amp;rsquo;obtenir la liste des canaux.&lt;/li>
&lt;li>&lt;code>channels:history&lt;/code> : Permission de lire l&amp;rsquo;historique des messages passés d&amp;rsquo;un canal.&lt;/li>
&lt;/ul>
&lt;p>Conformément au principe fondamental de sécurité &amp;ldquo;Principe du moindre privilège (Principle of Least Privilege)&amp;rdquo;, c&amp;rsquo;est une règle d&amp;rsquo;or de &lt;strong>ne demander que les portées (scopes) qui sont absolument indispensables pour les fonctionnalités fournies par l&amp;rsquo;application&lt;/strong>. Par exemple, pour une application qui &amp;ldquo;ne fait qu&amp;rsquo;envoyer des notifications&amp;rdquo;, il faut demander uniquement &lt;code>chat:write&lt;/code>, et non &lt;code>channels:history&lt;/code> (permission de lire toutes les conversations passées). Cela permet de minimiser les dégâts dans le cas improbable où l&amp;rsquo;application serait piratée et le jeton divulgué.&lt;/p>
&lt;hr>
&lt;h1 id="7-sécurité-avancée--pkce-proof-key-for-code-exchange">7. Sécurité avancée : PKCE (Proof Key for Code Exchange)
&lt;/h1>&lt;p>Récemment, &lt;strong>PKCE (Proof Key for Code Exchange, RFC 7636, prononcé &amp;ldquo;pixy&amp;rdquo;)&lt;/strong> a été standardisé et est largement utilisé comme mécanisme pour renforcer encore la sécurité d&amp;rsquo;OAuth 2.0.&lt;/p>
&lt;p>À l&amp;rsquo;origine, PKCE a été conçu pour les &amp;ldquo;clients publics&amp;rdquo; qui ne peuvent pas stocker &lt;code>client_secret&lt;/code> en toute sécurité, tels que les applications natives (iOS/Android) ou les SPA (Single Page Applications). Cependant, à l&amp;rsquo;heure actuelle, dans les meilleures pratiques de sécurité (Draft OAuth 2.1), l&amp;rsquo;utilisation de PKCE est fortement recommandée même pour les &amp;ldquo;clients confidentiels&amp;rdquo; côté serveur.&lt;/p>
&lt;h2 id="mécanisme-de-pkce-et-contexte-mathématique">Mécanisme de PKCE et contexte mathématique
&lt;/h2>&lt;p>PKCE prouve cryptographiquement que &amp;ldquo;la personne qui a initié la demande d&amp;rsquo;autorisation&amp;rdquo; et &amp;ldquo;la personne qui demande l&amp;rsquo;échange du jeton&amp;rdquo; sont identiques.&lt;/p>
&lt;ol>
&lt;li>Le client génère une chaîne aléatoire &lt;strong>&lt;code>code_verifier&lt;/code>&lt;/strong> (de 43 à 128 caractères).&lt;/li>
&lt;li>Il hache ceci avec &lt;strong>SHA-256&lt;/strong> et l&amp;rsquo;encode en BASE64URL pour en faire le &lt;strong>&lt;code>code_challenge&lt;/code>&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;p>Exprimé sous forme mathématique, cela donne :&lt;/p>
$$
\text{code\_challenge} = \text{BASE64URL-ENCODE}( \text{SHA256}( \text{ASCII}(\text{code\_verifier}) ) )
$$&lt;ol start="3">
&lt;li>Lors de l&amp;rsquo;exécution de &lt;code>/slack/install&lt;/code>, le client envoie &lt;code>code_challenge&lt;/code> et &lt;code>code_challenge_method=S256&lt;/code> en plus de &lt;code>state&lt;/code> au serveur d&amp;rsquo;autorisation (Slack) (Slack les sauvegarde temporairement).&lt;/li>
&lt;li>Après le rappel, lors de l&amp;rsquo;échange de jeton (&lt;code>/api/oauth.v2.access&lt;/code>), le &lt;strong>&lt;code>code_verifier&lt;/code>&lt;/strong> original (avant hachage) est envoyé.&lt;/li>
&lt;li>Le serveur d&amp;rsquo;autorisation (Slack) hache lui-même avec SHA-256 le &lt;code>code_verifier&lt;/code> reçu et vérifie s&amp;rsquo;il correspond exactement au &lt;code>code_challenge&lt;/code> sauvegardé à l&amp;rsquo;étape 3.&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
sequenceDiagram
participant C as &amp;#34;Client&amp;#34;
participant AS as &amp;#34;Authorization Server&amp;#34;
Note over C: &amp;#34;code_verifier = Chaîne aléatoire&amp;#34;&amp;lt;br/&amp;gt;&amp;#34;code_challenge = SHA256(code_verifier)&amp;#34;
C-&amp;gt;&amp;gt;AS: &amp;#34;Demande d&amp;#39;autorisation (Envoie code_challenge)&amp;#34;
Note over AS: &amp;#34;Conserve code_challenge&amp;#34;
AS--&amp;gt;&amp;gt;C: &amp;#34;Émission du code d&amp;#39;autorisation (code)&amp;#34;
C-&amp;gt;&amp;gt;AS: &amp;#34;Demande de jeton (Envoie code + code_verifier)&amp;#34;
Note over AS: &amp;#34;SHA256(verifier reçu) == challenge conservé ?&amp;#34;
AS--&amp;gt;&amp;gt;C: &amp;#34;Vérification réussie : Émission du jeton d&amp;#39;accès&amp;#34;
&lt;/pre>
&lt;p>Grâce à ce mécanisme, même si le &amp;ldquo;code d&amp;rsquo;autorisation (code)&amp;rdquo; est volé par une application malveillante ou l&amp;rsquo;écoute d&amp;rsquo;un canal de communication, l&amp;rsquo;attaquant ne connaît pas le &lt;code>code_verifier&lt;/code> original (en raison de la nature de la fonction de hachage unidirectionnelle SHA-256, il est impossible de déduire le verifier à partir du challenge), et il ne peut donc pas obtenir de jeton d&amp;rsquo;accès.&lt;/p>
&lt;p>Actuellement, le support de PKCE progresse dans certains nouveaux flux de l&amp;rsquo;API Slack et d&amp;rsquo;autres API SaaS modernes (Auth0, Okta, X/Twitter API v2, etc.), et cest une technologie que les développeurs devraient adopter activement.&lt;/p>
&lt;hr>
&lt;h1 id="8-gestion-et-exploitation-sécurisées-des-jetons-daccès">8. Gestion et exploitation sécurisées des jetons d&amp;rsquo;accès
&lt;/h1>&lt;p>Enfin, voici les meilleures pratiques concernant la méthode de sauvegarde des jetons d&amp;rsquo;accès obtenus.&lt;/p>
&lt;h2 id="1-le-cryptage-est-obligatoire-pour-la-sauvegarde-dans-la-base-de-données">1. Le cryptage est obligatoire pour la sauvegarde dans la base de données
&lt;/h2>&lt;p>Le jeton d&amp;rsquo;accès (&lt;code>xoxb-...&lt;/code>) est la &amp;ldquo;clé de rechange&amp;rdquo; pour votre espace de travail Slack. Ne le stockez pas en texte clair (plain text) dans une base de données (MySQL, PostgreSQL, MongoDB, etc.). Dans le cas improbable où la base de données fuirait en raison d&amp;rsquo;une injection SQL, ce serait une catastrophe majeure où les Slack de tous les clients seraient piratés.&lt;/p>
&lt;p>Assurez-vous toujours de le crypter au niveau de l&amp;rsquo;application en utilisant une cryptographie symétrique forte comme &lt;strong>AES-256-GCM&lt;/strong> avant de le sauvegarder dans la base de données. La clé principale (master key) pour le cryptage/décryptage doit être strictement gérée à l&amp;rsquo;aide d&amp;rsquo;un service de gestion des clés sécurisé tel qu&amp;rsquo;AWS KMS (Key Management Service) ou GCP Cloud KMS.&lt;/p>
&lt;h2 id="2-rotation-des-jetons-token-rotation">2. Rotation des jetons (Token Rotation)
&lt;/h2>&lt;p>Continuer à utiliser un jeton valide à long terme comporte des risques. Les implémentations récentes d&amp;rsquo;OAuth recommandent d&amp;rsquo;incorporer un mécanisme pour réémettre de nouveaux jetons d&amp;rsquo;accès toutes les quelques heures en utilisant un &amp;ldquo;Jeton de rafraîchissement (Refresh Token)&amp;rdquo; (Token Rotation). Dans l&amp;rsquo;API Slack également, il est possible d&amp;rsquo;activer la rotation des jetons dans les paramètres d&amp;rsquo;options.&lt;/p>
&lt;hr>
&lt;h1 id="résumé">Résumé
&lt;/h1>&lt;p>Dans cet article, nous avons expliqué en détail le flux d&amp;rsquo;octroi de code d&amp;rsquo;autorisation d&amp;rsquo;OAuth 2.0 avec des codes d&amp;rsquo;implémentation Node.js spécifiques pour l&amp;rsquo;intégration de Slack App.&lt;/p>
&lt;ol>
&lt;li>En étant conscient des &lt;strong>4 rôles (RO, Client, AS, RS)&lt;/strong>, l&amp;rsquo;architecture de l&amp;rsquo;ensemble du système devient claire.&lt;/li>
&lt;li>L&amp;rsquo;&lt;strong>octroi de code d&amp;rsquo;autorisation&lt;/strong> garantit la sécurité en utilisant habilement le chemin de communication entre le navigateur et le serveur (canal frontal/arrière).&lt;/li>
&lt;li>Comprendre les mécanismes cryptographiques sous-jacents, tels que la protection CSRF par le &lt;strong>paramètre &lt;code>state&lt;/code>&lt;/strong> et la prévention de l&amp;rsquo;interception du code d&amp;rsquo;autorisation par &lt;strong>PKCE&lt;/strong>, est un raccourci vers une implémentation sécurisée.&lt;/li>
&lt;li>La conception des portées (scopes) basée sur le &lt;strong>principe du moindre privilège&lt;/strong> et le cryptage lors de la sauvegarde dans la base de données sont des éléments absolument indispensables pour l&amp;rsquo;exploitation.&lt;/li>
&lt;/ol>
&lt;p>OAuth 2.0 est très profond et la RFC à elle seule a des spécifications massives, mais en apprenant de manière pratique en ciblant une plateforme réelle (Slack) de cette façon, vous devriez être en mesure de ressentir sa philosophie de conception raffinée et ses mécanismes de sécurité robustes. Nous espérons que les connaissances de cet article vous seront utiles dans le développement de vos futures applications et l&amp;rsquo;implémentation de vos intégrations d&amp;rsquo;API.&lt;/p></description></item></channel></rss>