Skip to main content

Création d’un bouton « Se connecter avec GitHub » avec une application GitHub App

Suivez ce tutoriel pour écrire du code Ruby afin de générer un jeton d’accès utilisateur via le flux d’application web pour votre GitHub App.

Introduction

Ce tutoriel montre comment créer un bouton « Se connecter avec GitHub » pour un site web. Le site web utilise une GitHub App pour générer un jeton d’accès utilisateur via le flux d’application web. Le site web utilise ensuite le jeton d’accès utilisateur afin d’effectuer des demandes d’API pour le compte de l’utilisateur authentifié.

Ce tutoriel utilise Ruby, mais vous pouvez utiliser le flux d’application web avec tout langage de programmation utilisé pour le développement web.

À propos du flux d’application web et des jetons d’accès utilisateur

Votre application doit utiliser un jeton d’accès utilisateur si vous souhaitez attribuer des actions de l’application à un utilisateur. Pour plus d’informations, consultez « Authentification auprès d’une application GitHub pour le compte d’un utilisateur ».

Deux méthodes permettent de générer un jeton d’accès utilisateur pour une GitHub App : le flux d’application web et le flux d’appareil. Si votre application a accès à une interface web, vous devez utiliser le flux d’application web. Si votre application n’a pas accès à une interface web, vous devez utiliser le flux d’appareil à la place. Pour plus d’informations, consultez « Génération d’un jeton d’accès utilisateur pour une application GitHub » et « Création d’une interface CLI avec une application GitHub App ».

Prérequis

Ce tutoriel part du principe que vous avez déjà inscrit une GitHub App. Pour plus d’informations sur l’inscription d’une GitHub App, consultez « Inscription d’une application GitHub ».

Avant de suivre ce tutoriel, vous devez définir une URL de rappel pour votre application. Ce tutoriel utilise un serveur Sinatra local avec l’URL par défaut http://localhost:4567. Par exemple, pour utiliser l’URL par défaut d’une application Sinatra locale, votre URL de rappel peut être http://localhost:4567/github/callback. Une fois que vous êtes prêt à déployer votre application, vous pouvez modifier l’URL de rappel pour utiliser l’adresse de votre serveur en ligne. Pour plus d’informations sur la mise à jour de l’URL de rappel de votre application, consultez « Modification d’une inscription d’application GitHub » et « À propos de l’URL de rappel d’autorisation utilisateur ».

Ce tutoriel part du principe que vous avez des connaissances de base de Ruby et du système de modèles Ruby, ERB. Pour plus d’informations, consultez Ruby et ERB.

Installer des dépendances

Ce tutoriel utilise le gem Ruby, Sinatra, pour créer une application web avec Ruby. Pour plus d’informations, consultez le fichier LISEZMOI de Sinatra.

Ce tutoriel utilise le gem Ruby, dotenv, pour accéder aux valeurs stockées dans un fichier .env. Pour plus d’informations, consultez le fichier LISEZMOI de dotenv.

Pour suivre ce tutoriel, vous devez installer les gems Sinatra et dotenv dans votre projet Ruby. Vous pouvez par exemple effectuer cette opération avec Bundler :

  1. Si Bundler n’est pas installé, exécutez la commande suivante dans votre terminal :

    gem install bundler
    
  2. Si un Gemfile n’est pas installé, exécutez la commande suivante dans votre terminal :

    bundle init
    
  3. Si un Gemfile.lock n’est pas installé, exécutez la commande suivante dans votre terminal :

    bundle install
    
  4. Installez les gems en exécutant les commandes suivantes dans votre terminal :

    bundle add sinatra
    
    bundle add dotenv
    

Stocker l’ID client et le secret client

Ce tutoriel vous montre comment stocker l’ID client et le secret client dans des variables d’environnement et y accéder avec ENV.fetch. Quand vous déployez votre application, vous voudrez modifier la façon dont vous stockez l’ID client et le secret client. Pour plus d’informations, consultez « Stocker votre secret client en lieu sûr ».

  1. Dans le coin supérieur droit de n’importe quelle page sur GitHub, cliquez sur votre photo de profil.

  2. Accédez aux paramètres de votre compte.

    • Pour une application appartenant à un compte personnel, cliquez sur Paramètres.
    • Pour une application appartenant à une organisation :
      1. Cliquez sur Vos organisations.
      2. À droite de l’organisation, cliquez sur Paramètres.
  3. Dans la barre latérale gauche, cliquez sur Paramètres de développeur.

  4. Dans la barre latérale à gauche, cliquez sur GitHub Apps .

  5. À côté de l’GitHub App que vous souhaitez utiliser, cliquez sur Modifier.

  6. Dans la page des paramètres de l’application, recherchez l’ID client de votre application. Vous l’ajouterez à un fichier .env à une étape ultérieure. Notez que l’ID client est différent de l’ID de l’application.

  7. Dans la page des paramètres de l’application, cliquez sur Générer un nouveau secret client. Vous ajouterez le secret client à un fichier .env à une étape ultérieure.

  8. Créez un fichier appelé .env au même niveau que votre Gemfile.

  9. Si votre projet n’a pas encore de fichier .gitignore, créez un fichier .gitignore au même niveau que votre Gemfile.

  10. Ajoutez .env à votre fichier .gitignore. Cette action vous empêche de commiter accidentellement votre secret client. Pour plus d’informations sur les fichiers .gitignore, consultez « Ignorer des fichiers ».

  11. Ajoutez le contenu suivant à votre fichier .env. Remplacez YOUR_CLIENT_ID par l’ID client de votre application. Remplacez YOUR_CLIENT_SECRET par le secret client de votre application.

    CLIENT_ID="YOUR_CLIENT_ID"
    CLIENT_SECRET="YOUR_CLIENT_SECRET"
    

Ajouter du code pour générer un jeton d’accès utilisateur

Pour obtenir un jeton d’accès utilisateur, vous devez d’abord inviter l’utilisateur à autoriser votre application. Quand un utilisateur autorise votre application, il est redirigé vers l’URL de rappel de votre application. La demande pour l’URL de rappel inclut un paramètre de requête code. Quand votre application obtient une demande de traitement de cette URL de rappel, vous pouvez échanger le paramètre code contre un jeton d’accès utilisateur.

Ces étapes vous guident dans l’écriture de code pour générer un jeton d’accès utilisateur. Pour passer au code final, consultez « Exemple de code complet ».

  1. Dans le même répertoire que votre fichier .env, créez un fichier Ruby pour contenir le code qui va générer un jeton d’accès utilisateur. Dans ce tutoriel, le fichier est nommé app.rb.

  2. En haut de app.rb, ajoutez ces dépendances :

    Ruby
    require "sinatra"
    require "dotenv/load"
    require "net/http"
    require "json"
    

    Les dépendances sinatra et dotenv/load utilisent les gems que vous avez installés précédemment. net/http et json font partie de la bibliothèque standard Ruby.

  3. Ajoutez le code suivant à app.rb pour obtenir l’ID client et le secret client de votre application à partir de votre fichier .env.

    Ruby
    CLIENT_ID = ENV.fetch("CLIENT_ID")
    CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")
    
  4. Ajoutez le code suivant à app.rb pour afficher un lien qui invitera les utilisateurs à authentifier votre application.

    Ruby
    get "/" do
      link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>'
      erb link
    end
    
  5. Ajoutez le code suivant à app.rb pour gérer les demandes à l’URL de rappel de votre application et obtenir le paramètre code à partir de la demande. Remplacez CALLBACK_URL par l’URL de rappel de votre application, moins le domaine. Par exemple, si votre URL de rappel est http://localhost:4567/github/callback, remplacez CALLBACK_URL par /github/callback.

    Ruby
    get "CALLBACK_URL" do
      code = params["code"]
      render = "Successfully authorized! Got code #{code}."
      erb render
    end
    

    Actuellement, le code affiche juste un message avec le paramètre code. Les étapes suivantes vont développer ce bloc de code.

  6. Vous pouvez également vérifier votre progression :

    app.rb se présente maintenant comme suit, où CALLBACK_URL est l’URL de rappel de votre application, moins le domaine :

    Ruby
    require "sinatra"
    require "dotenv/load"
    require "net/http"
    require "json"
    
    CLIENT_ID = ENV.fetch("CLIENT_ID")
    CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")
    
    get "/" do
      link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>'
      erb link
    end
    
    get "CALLBACK_URL" do
      code = params["code"]
      render = "Successfully authorized! Got code #{code}."
      erb render
    end
    
    1. Dans votre terminal, dans le répertoire où app.rb est stocké, exécutez ruby app.rb. Un serveur Sinatra local doit démarrer.

    2. Dans votre navigateur, accédez à http://localhost:4567. Vous devriez voir un lien avec le texte « Se connecter à GitHub ».

    3. Cliquez sur le lien « Se connecter à GitHub ».

      Si vous n’avez pas autorisé l’application, le fait de cliquer sur le lien devrait vous rediriger vers http(s)://HOSTNAME/login/oauth/authorize?client_id=CLIENT_ID, où CLIENT_ID est l’ID client de votre application. Il s’agit d’une page GitHub qui invite les utilisateurs à autoriser votre application. Si vous cliquez sur le bouton autorisant votre application, vous accédez à l’URL de rappel de votre application.

      Si vous avez déjà autorisé votre application et que l’autorisation n’a pas été révoquée, ignorez l’invite d’autorisation et accédez directement à l’URL de rappel. Vous pouvez révoquer votre autorisation précédente si vous souhaitez voir l’invite d’autorisation. Pour plus d’informations, consultez « Examen et révocation de l’autorisation donnée aux applications GitHub ».

    4. La page d’URL de rappel, accessible en cliquant sur le lien « Se connecter à GitHub », puis en autorisant l’application si vous y êtes invité, devrait afficher le texte « Autorisation acceptée. Code agc622abb6135be5d1f2 obtenu. » ou similaire.

    5. Dans votre terminal où Sinatra s’exécute, arrêtez le serveur en entrant Ctrl+C.

  7. Remplacez le contenu de app.rb par le code suivant, où CALLBACK_URL est l’URL de rappel de votre application, moins le domaine.

    Ce code ajoute une logique pour échanger le paramètre code contre un jeton d’accès utilisateur :

    • La fonction parse_response analyse la réponse de l’API GitHub.
    • La fonction exchange_code échange le paramètre code contre un jeton d’accès utilisateur.
    • Le gestionnaire de la demande d’URL de rappel appelle maintenant exchange_code pour échanger le paramètre de code contre un jeton d’accès utilisateur.
    • La page de rappel montre maintenant du texte pour indiquer qu’un jeton a été généré. Si la génération du jeton n’a pas réussi, la page indique cet échec.
    Ruby
    require "sinatra"
    require "dotenv/load"
    require "net/http"
    require "json"
    
    CLIENT_ID = ENV.fetch("CLIENT_ID")
    CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")
    
    def parse_response(response)
      case response
      when Net::HTTPOK
        JSON.parse(response.body)
      else
        puts response
        puts response.body
        {}
      end
    end
    
    def exchange_code(code)
      params = {
        "client_id" => CLIENT_ID,
        "client_secret" => CLIENT_SECRET,
        "code" => code
      }
      result = Net::HTTP.post(
        URI("http(s)://HOSTNAME/login/oauth/access_token"),
        URI.encode_www_form(params),
        {"Accept" => "application/json"}
      )
    
      parse_response(result)
    end
    
    get "/" do
      link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>'
      erb link
    end
    
    get "CALLBACK_URL" do
      code = params["code"]
    
      token_data = exchange_code(code)
    
      if token_data.key?("access_token")
        token = token_data["access_token"]
    
        render = "Successfully authorized! Got code #{code} and exchanged it for a user access token ending in #{token[-9..-1]}."
        erb render
      else
        render = "Authorized, but unable to exchange code #{code} for token."
        erb render
      end
    end
    
  8. Vous pouvez également vérifier votre progression :

    1. Dans votre terminal, dans le répertoire où app.rb est stocké, exécutez ruby app.rb. Un serveur Sinatra local doit démarrer.
    2. Dans votre navigateur, accédez à http://localhost:4567. Vous devriez voir un lien avec le texte « Se connecter à GitHub ».
    3. Cliquez sur le lien « Se connecter à GitHub ».
    4. Si vous y êtes invité, autorisez votre application.
    5. La page d’URL de rappel, accessible en cliquant sur le lien « Se connecter à GitHub », puis en autorisant l’application si vous y êtes invité, devrait afficher le texte « Autorisation acceptée. Nous avons obtenu le code 4acd44861aeda86dacce et l’avons échangé contre un jeton d’accès utilisateur se terminant par 2zU5kQziE. »
    6. Dans votre terminal où Sinatra s’exécute, arrêtez le serveur en entrant Ctrl+C.
  9. Maintenant que vous disposez d’un jeton d’accès utilisateur, vous pouvez l’utiliser pour effectuer des demandes d’API au nom de l’utilisateur. Par exemple :

    Ajoutez cette fonction à app.rb pour obtenir les informations sur l’utilisateur avec le point de terminaison de l’API REST /user :

    Ruby
    def user_info(token)
      uri = URI("http(s)://HOSTNAME/api/v3/user")
    
      result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        body = {"access_token" => token}.to_json
    
        auth = "Bearer #{token}"
        headers = {"Accept" => "application/json", "Content-Type" => "application/json", "Authorization" => auth}
    
        http.send_request("GET", uri.path, body, headers)
      end
    
      parse_response(result)
    end
    

    Mettez à jour le gestionnaire de rappel pour appeler la fonction user_info et afficher le nom et la connexion GitHub de l’utilisateur. N’oubliez pas de remplacer CALLBACK_URL par l’URL de rappel de votre application, moins le domaine.

    Ruby
    get "CALLBACK_URL" do
      code = params["code"]
    
      token_data = exchange_code(code)
    
      if token_data.key?("access_token")
        token = token_data["access_token"]
    
        user_info = user_info(token)
        handle = user_info["login"]
        name = user_info["name"]
    
        render = "Successfully authorized! Welcome, #{name} (#{handle})."
        erb render
      else
        render = "Authorized, but unable to exchange code #{code} for token."
        erb render
      end
    end
    
  10. Vérifiez votre code par rapport à l’exemple de code complet présenté dans la section suivante. Vous pouvez tester votre code en suivant les étapes décrites dans la section « Test » sous l’exemple de code complet.

Exemple de code complet

Il s’agit de l’exemple de code complet décrit dans la section précédente.

Remplacez CALLBACK_URL par l’URL de rappel de votre application, moins le domaine. Par exemple, si votre URL de rappel est http://localhost:4567/github/callback, remplacez CALLBACK_URL par /github/callback.

Ruby
require "sinatra"
require "dotenv/load"
require "net/http"
require "json"

CLIENT_ID = ENV.fetch("CLIENT_ID")
CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")

def parse_response(response)
  case response
  when Net::HTTPOK
    JSON.parse(response.body)
  else
    puts response
    puts response.body
    {}
  end
end

def exchange_code(code)
  params = {
    "client_id" => CLIENT_ID,
    "client_secret" => CLIENT_SECRET,
    "code" => code
  }
  result = Net::HTTP.post(
    URI("http(s)://HOSTNAME/login/oauth/access_token"),
    URI.encode_www_form(params),
    {"Accept" => "application/json"}
  )

  parse_response(result)
end

def user_info(token)
  uri = URI("http(s)://HOSTNAME/api/v3/user")

  result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    body = {"access_token" => token}.to_json

    auth = "Bearer #{token}"
    headers = {"Accept" => "application/json", "Content-Type" => "application/json", "Authorization" => auth}

    http.send_request("GET", uri.path, body, headers)
  end

  parse_response(result)
end

get "/" do
  link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>'
  erb link
end

get "CALLBACK_URL" do
  code = params["code"]

  token_data = exchange_code(code)

  if token_data.key?("access_token")
    token = token_data["access_token"]

    user_info = user_info(token)
    handle = user_info["login"]
    name = user_info["name"]

    render = "Successfully authorized! Welcome, #{name} (#{handle})."
    erb render
  else
    render = "Authorized, but unable to exchange code #{code} for token."
    erb render
  end
end

Test

Ce tutoriel part du principe que le code de votre application est stocké dans un fichier nommé app.rb et que vous utilisez l’URL par défaut d’une application Sinatra locale, http://localhost:4567.

  1. Dans votre terminal, dans le répertoire où app.rb est stocké, exécutez ruby app.rb. Un serveur Sinatra local doit démarrer.

  2. Dans votre navigateur, accédez à http://localhost:4567. Vous devriez voir un lien avec le texte « Se connecter à GitHub ».

  3. Cliquez sur le lien « Se connecter à GitHub ».

    Si vous n’avez pas autorisé l’application, le fait de cliquer sur le lien devrait vous rediriger vers http(s)://HOSTNAME/login/oauth/authorize?client_id=CLIENT_ID, où CLIENT_ID est l’ID client de votre application. Il s’agit d’une page GitHub qui invite les utilisateurs à autoriser votre application. Si vous cliquez sur le bouton autorisant votre application, vous accédez à l’URL de rappel de votre application.

    Si vous avez déjà autorisé votre application et que l’autorisation n’a pas été révoquée, ignorez l’invite d’autorisation et accédez directement à l’URL de rappel. Vous pouvez révoquer votre autorisation précédente si vous souhaitez voir l’invite d’autorisation. Pour plus d’informations, consultez « Examen et révocation de l’autorisation donnée aux applications GitHub ».

  4. La page d’URL de rappel, accessible en cliquant sur le lien « Se connecter à GitHub », puis en autorisant l’application si vous y êtes invité, devrait afficher le texte « Autorisation acceptée. Bienvenue, Mona Lisa (octocat). »

  5. Dans votre terminal où Sinatra s’exécute, arrêtez le serveur en entrant Ctrl+C.

Étapes suivantes

Stocker votre secret client en lieu sûr

Vous ne devez jamais révéler le secret client de votre application. Ce tutoriel a stocké le secret client dans un fichier .env gitignored et a accédé à la valeur avec ENV.fetch. Quand vous déployez votre application, choisissez un moyen sécurisé de stocker le secret client et de mettre à jour votre code pour obtenir la valeur en conséquence.

Vous pouvez par exemple stocker le secret dans une variable d’environnement sur le serveur sur lequel votre application est déployée. Vous pouvez également utiliser un service de gestion des secrets comme Azure Key Vault.

Mettre à jour l’URL de rappel pour le déploiement

Ce tutoriel a utilisé une URL de rappel commençant par http://localhost:4567. Toutefois, http://localhost:4567 est uniquement disponible en local sur votre ordinateur quand vous démarrez le serveur Sinatra. Avant de déployer votre application, vous devez mettre à jour l’URL de rappel pour utiliser l’URL de rappel dont vous vous servez en production. Pour plus d’informations sur la mise à jour de l’URL de rappel de votre application, consultez « Modification d’une inscription d’application GitHub » et « À propos de l’URL de rappel d’autorisation utilisateur ».

Gérer plusieurs URL de rappel

Ce tutoriel a utilisé une seule URL de rappel, mais votre application peut avoir jusqu’à 10 URL de rappel. Si vous souhaitez utiliser plusieurs URL de rappel :

Spécifier d'autres paramètres

Quand vous créez un lien vers http(s)://HOSTNAME/login/oauth/authorize, vous pouvez transmettre des paramètres de requête supplémentaires. Pour plus d’informations, consultez « Génération d’un jeton d’accès utilisateur pour une application GitHub ».

Contrairement à un jeton OAuth traditionnel, le jeton d’accès utilisateur n’utilise pas d’étendues, donc vous ne pouvez pas spécifier d’étendues via le paramètre scope. À la place, il utilise des autorisations affinées. Un jeton d’accès utilisateur dispose uniquement des autorisations dont disposent l’utilisateur et l’application.

Ajustez le code selon les besoins de votre application

Ce tutoriel a montré comment afficher des informations sur l’utilisateur authentifié, mais vous pouvez ajuster ce code pour effectuer d’autres actions. N’oubliez pas de mettre à jour les autorisations de votre application si des autorisations supplémentaires sont nécessaires pour les demandes d’API que vous souhaitez effectuer. Pour plus d’informations, consultez « Choix des autorisations pour une application GitHub ».

Ce tutoriel a stocké tout le code dans un fichier unique, mais vous pouvez déplacer des fonctions et des composants dans des fichiers distincts.

Stocker les jetons en toute sécurité

Ce tutoriel génère un jeton d’accès utilisateur. Sauf si vous avez refusé l’expiration des jetons d’accès utilisateur, le jeton d’accès utilisateur expire au bout de huit heures. Vous recevez également un jeton d’actualisation qui peut regénérer un jeton d’accès utilisateur. Pour plus d’informations, consultez « Actualisation des jetons d’accès utilisateur ».

Si vous prévoyez d’interagir davantage avec les API de GitHub, stockez le jeton pour l’utiliser ultérieurement. Si vous choisissez de stocker le jeton d’accès utilisateur ou le jeton d’actualisation, vous devez le stocker en lieu sûr. Vous ne devez jamais révéler le jeton.

Pour plus d’informations, consultez « Meilleures pratiques pour la création d’une application GitHub ».

Suivre les bonnes pratiques

Vous devez vous efforcer de suivre les bonnes pratiques avec votre GitHub App. Pour plus d’informations, consultez « Meilleures pratiques pour la création d’une application GitHub ».