Est-ce qu’il vous est déjà arrivé de devoir implémenter une authentification dans votre application Shiny pour la veille ?
Hélas pour moi, je suis passé par là.
Il y a quelques années, un client m’a contacté avec une demande urgente :
- Ajouter une page d’accueil à leur application Shiny existante
- Intégrer un formulaire de connexion dans cette page d’accueil
- Et, bien sûr, configurer tout le mécanisme d’authentification
Le hic ? Ils avaient déjà dépassé leur propre deadline.
À la fin de notre réunion de lancement, j’avais une semaine pour comprendre le code de leur application, implémenter le système d’authentification, et concevoir une page d’accueil soignée. Même avec l’aide d’un ami pour le design, la pression était immense.
Et la cerise sur le gâteau ? Je n’avais jamais implémenté de système d’authentification avant.
Au début de mes recherches, je suis tombé sur le package shinymanager
. C’était un soulagement… jusqu’à ce que je réalise qu’il manquait quelques fonctionnalités cruciales nécessaires pour ce projet.
Je n’ai pas dormi beaucoup cette semaine là.
Je me suis plongé dans le code du package et je l’ai étendu pour répondre aux exigences du client. C’était aussi la première fois que j’avais affaire au paradigme POO R6
de R.
Quelques jours plus tard, j’ai poussé mon code sur leur repo Git :
Mes premiers commits sur ce projet
Et après ça …
Rien.
Aucun retour. Aucune confirmation. Silence radio.
Est-ce qu’ils en étaient satisfaits ? Est-ce que l’application a été utilisée ? Je n’ai plus jamais eu de nouvelles. J’ai reçu mon paiement de la plateforme de freelance, et je suis passé à autre chose.
La conclusion que j’ai tirée de cette expérience, c’est que mettre en place un système d’authentification personnalisé est un calvaire. Même avec des outils comme shinymanager
. On ne m’y aurait pas repris deux fois.
Depuis, j’ai eu l’occasion de tester d’autres packages et d’autres outils. Et il y en a un qui se démarque du lot : Auth0.
Auth0 est une plateforme d’authentification robuste qui simplifie grandement la sécurisation de votre application.
Pourquoi Auth0 ?
Les avantages sont nombreux :
- C’est simple à configurer
- C’est sécurisé
- Il y a une tonne de fonctionnalités (vous pouvez même en ajouter avec des scripts personnalisés)
- L’interface utilisateur du portail d’authentification est entièrement personnalisable
- C’est gratuit jusqu’à 7 500 utilisateurs actifs par mois (avec les fonctionnalités de base)
Que vous soyez un développeur Shiny chevronné ou débutant, mettre en place un système d’authentification sécurisé peut sembler intimidant.
Qu’est-ce qui rend ce guide différent ?
Ce n’est pas qu’un tutoriel basique sur Auth0 qui présente les choses de manière superficielle. C’est le guide ultime. C’est le premier et le dernier tutoriel dont vous aurez besoin pour intégrer Auth0 à votre application Shiny. Voilà un aperçu des sujets que nous allons aborder :
- Comprendre l’Authentification : qu’est-ce que c’est et comment gérer ça dans Shiny.
- Choisir la Bonne Solution : parmi les solutions existantes, identifier la meilleure implémentation pour vos besoins spécifiques.
- Implémenter Auth0 : des instructions détaillées pour ajouter un portail d’authentification Auth0 à votre application Shiny.
- Améliorer votre portail : des conseils pour améliorer et personnaliser votre portail d’authentification.
- Astuces avancées : des solutions aux problèmes et questions courantes que vous pourriez rencontrer.
À la fin de ce guide, vous aurez une application Shiny entièrement authentifiée utilisant Auth0.
Allons-y, Alonso !
1. Comprendre l’authentification
1.1. Identification vs Authentification vs Autorisation
Tout d’abord, un point de vocabulaire. Quelle est la différence entre authentification, identification et autorisation ?
- L’identification est l’action de déclarer son identité.
- L’authentification est le processus de vérification de cette identité. Par exemple, quelqu’un vérifie ma carte d’identité pour s’assurer que je suis bien la personne que je prétends être.
- L’autorisation concerne l’attribution ou le refus d’accès à une ressource pour une personne/identité donnée.
Quand je me connecte avec un identifiant et un mot de passe, je m’authentifie. L’identifiant représente mon identité, et mon identité est vérifiée quand je fournis le bon mot de passe qui lui est associé.
Mais s’authentifier n’est pas suffisant pour accéder à du contenu. Pour cela, il faut aussi être autorisé. Le système va vérifier que mon identité est autorisée à accéder au contenu que j’essaie d’atteindre. Par exemple, si je n’ai pas les droits administrateur, je peux être authentifié mais cela ne suffira pas pour accéder à la page d’administration.
En revanche, s’authentifier n’est pas toujours nécessaire. Dans certains cas, il suffit de fournir un mot de passe pour être autorisé. Dans ce cas, il n’y a ni identification ni authentification. Tant que vous connaissez le mot de passe, vous pouvez entrer. On se ficher de qui vous êtes.
A partir de maintenant, j’utiliserai le terme authentification par simplicité, mais gardez à l’esprit que ça englobe à la fois l’authentification ET l’autorisation.
1.2. Faut-il gérer l’authentification depuis le code de l’appli Shiny ?
Commençons par un rappel sur les échanges client-serveur qui se produisent dans une application Shiny classique (i.e. sans authentification) :
- Votre navigateur envoie une requête via internet
- Un serveur web* (comme nginx ou Apache) reçoit la requête et la transmet au serveur Shiny
- Le serveur Shiny traite la requête et renvoie une réponse
- La réponse revient à votre navigateur en suivant le même chemin
*Un serveur web est un logiciel installé sur un serveur dont le rôle est de gérer le trafic entrant et de le rediriger vers le bon récipient (le serveur Shiny, par exemple). Il peut aussi assurer d’autres fonctionnalités, comme le chiffrement des communications (avec HTTPS/TLS), etc.
Où est-ce qu’on pourrait implémenter un système d’authentification dans cette séquence ?
- Sur votre ordinateur
- Durant le transit entre client et serveur
- Au niveau du serveur web (nginx/Apache)
- Dans l’application Shiny elle-même
Les options 1 et 2 ne sont pas sécurisées. L’authentification doit se faire sur des machines que nous contrôlons. Il nous reste donc les options 3 et 4, qui sont toutes deux valables avec différents avantages et inconvénients :
Méthode 1 : Authentification au niveau du serveur web
Dans les grandes lignes :
- Votre navigateur envoie une requête HTTP pour accéder à l’application Shiny
- Le serveur web intercepte la requête et vérifie le statut d’authentification*
- Si non authentifié, l’utilisateur est redirigé vers une page de login
- Si authentifié, la requête est transmise au serveur Shiny
- Le serveur Shiny traite la requête et renvoie une réponse
- La réponse revient à votre navigateur en passant par le serveur web
*Pour l’instant, on va ignorer comment l’authentification est implémentée. On suppose juste qu’un “logiciel” est capable de vérifier si l’utilisateur est authentifié ou non.
Quels sont les avantages et inconvénients de cette méthode ?
Avantages | Inconvénients |
---|---|
Meilleure séparation des responsabilités | Requiert plus de connaissances en administration serveur |
Peut protéger plusieurs applications | Implémentation générique, moins personnalisable pour une application donnée |
Souvent de meilleures performances |
Globalement, cette méthode est plus propre et plus sécurisée, mais plus complexe à implémenter. Je recommande cette option quand :
- Si vous avez déjà de l’expérience avec les systèmes d’authentification,
- Si vous n’avez pas peur de passer plus de temps à configurer votre serveur web qu’à coder en R,
- Si vous voulez avoir une séparation claire des responsabilités.
Méthode 2 : Authentification dans l’application Shiny
Dans les grandes lignes, cette méthode fonctionne comme suit :
- Votre navigateur envoie une requête HTTP pour accéder à l’application Shiny
- Le serveur web transmet la requête au serveur Shiny
- Le serveur Shiny passe la requête au module/fonction qui gère l’authentification
- Si l’authentification échoue, l’utilisateur voit une interface de connexion
- Si l’authentification réussit, la requête est transmise au reste de l’application
- Le contenu de l’application (la réponse) est renvoyé dans le sens inverse jusqu’à votre navigateur
Avantages | Inconvénients |
---|---|
Plus flexible et personnalisable | Doit être implémenté pour chaque application |
Implémentation purement en R: pas d’administration système requise | Consomme des ressources de l’application |
Meilleure intégration dans la logique de l’application |
L’avantage principal de cette méthode est qu’elle est beaucoup plus facile à implémenter. Vous n’avez pas besoin de savoir configurer un serveur web comme Nginx, ou savoir comment envoyer des en-têtes HTTP de sécurité. Vous pouvez rester dans l’écosystème R.
Comment choisir la bonne méthode ?
Vous deviez vous en douter, mais il n’y a pas de méthode parfaite. Certaines solutions conviendront mieux à certaines situations.
Personellement, je préfère la méthode 1. Elle est plus propre et plus sécurisée. Vous authentifiez les utilisateurs avant qu’ils n’atteignent l’application Shiny et qu’une seule ligne de code R soit exécutée. Ils n’accéderont jamais au contenu de l’application s’ils ne peuvent pas s’authentifier, ce qui évite d’avoir à se soucier de vérouiller chaque bout de code de l’application derrière une vérification d’authentification.
Mais, dans la pratique, j’implémente beaucoup plus souvent la méthode 2. Parce qu’elle est moins coûteuse pour mes clients, et que je n’ai pas toujours les accès nécessaires pour configurer leurs serveurs.
Bon…
Juste avant, je vous ai parlé de “Module d’authentification Shiny” ou de “Couche d’authentification”, que j’ai un peu passés sous le tapis.
Il est temps de rentrer dans le vif du sujet et de comparer les différentes solutions existantes… et de vous montrer pourquoi Auth0 est probablement votre meilleur choix.
2. Choisir la bonne solution d’authentification
Quand vous implémentez un système d’authentification dans votre application Shiny, vous avez trois options principales :
- Construire votre propre solution d’authentification (à éviter)
- Utiliser un package R d’authentification pré-fait
- Utiliser un service d’authentification professionnel (language-agnostic)
Voici une vue d’ensemble des forces et faiblesses de ces approches :
Type de Solution | Sécurité | Fonctionnalités | Facilité d’utilisation | Coût | Recommandé pour |
---|---|---|---|---|---|
Solution maison | Faible-Moyenne | Limitées | Complexe | Gratuit | Jamais |
Package pré-fait | Moyenne | Basiques | Facile | Gratuit | Apps internes |
Service Auth | Élevée | Complètes | Moyenne | Gratuit-Premium | Apps en production |
Maintenant, passons en revue chacune de ces options.
2.1. Construire sa propre solution d’authentification
Mauvaise idée.
C’est tout un métier, et il est plus complexe que vous ne l’imaginez.
Il faut connaître les vulnérabilités de sécurité courantes, comme le détournement de session, l’injection SQL, le cross-site scripting, et j’en passe.
Il va falloir maintenir votre solution, la mettre à jour constamment contre les nouvelles vulnérabilités de sécurité, etc.
Vous allez passer un temps fou… à réinventer l’eau chaude. Et elle sera tiède.
A part si vous êtes un expert en sécurité ou si vous voulez faire l’exercice pour des raisons académiques, passez votre chemin.
2.2. Utiliser une solution existante
Il existe de plusieurs packages qui proposent une authentification clé en main pour votre application Shiny :
- shinymanager : Avec des identifiants chiffrés et un support SQL
- shinyauthr : Authentification simple basée sur les cookies
- login : Authentification basique
- polished : Solution plus complète avec gestion des utilisateurs
Ce sont de bonnes solutions pour des applications internes, quand vous avez besoin d’une implémentation rapide et que vous ne voulez pas passer par un service tiers.
Cependant, je ne pense pas qu’elles soient suffisamment sécurisées et complètes pour des applications publiques.
Elles ont été développées par des programmeurs R, des gens comme vous et moi. Ils s’y connaissent probablement plus que nous sur les questions de sécurité, mais ce ne sont pas nécessairement des experts en sécurité. Et il n’y a aucune garantie que leur travail soit régulièrement audité par des experts en sécurité.
De plus, il vont probablement manquer de fonctionnalités qui vous seront nécessaires tôt ou tard, comme :
- Gestion de sessions : Pour maintenir et renouveler les sessions avec des cookies
- Gestion des utilisateurs : Réinitialisation des mots de passe, envoi d’emails, vérification d’adresses email
- Authentification à deux facteurs
- Accès basé sur les rôles : Quand vous avez différents niveaux de permission (utilisateur, admin) ou une application qui s’adapte selon les données utilisateur
- Connexion sociale : Pour faciliter l’accès via Google, Facebook, Github, etc.
En résumé, ces packages sont parfaits pour du prototypage ou pour une application interne. Mais je ne les recommanderais pas pour une application en production.
2.3. Utiliser des services d’authentification professionnels
Utiliser des services professionnels vous offre plusieurs avantages :
- Construits et maintenus par des experts en sécurité : C’est LEUR métier. Ils mangent des vulnérabilités du noyau Linux au petit-déjeuner, et ils déploient les correctifs de sécurité avant même que la presse spécialisée n’ait eu vent du problème.
- Ensemble complet de fonctionnalités : Si vous voulez une fonctionnalité, il y a de grandes chances qu’ils l’aient déjà développée.
- Documentation et support complets : Ils ont une équipe dédiée pour vous aider.
Ces services professionnels sont :
- Auth0 (bien sûr)
- Okta
- Clerk
- AWS Cognito (ou l’équivalent chez Azure ou GCP)
- SuperTokens
- Et d’autres…
Bien sûr, ces services ont aussi des inconvénients :
- Vous allez peut-être devoir payer pour les utiliser.
- Ils ne sont pas toujours faciles à intégrer avec une application Shiny.
Et c’est pour ça que je recommande Auth0 aussi chaudement :
- Vous pouvez l’utiliser gratuitement jusqu’à 7500 utilisateurs actifs mensuels.
- C’est super facile à intégrer à une application Shiny grâce au package auth0.
Quid des autres solutions que tu as mentionnées ?
Je ne saurait pas quoi vous dire sur Okta, Clerk, ou SuperTokens. Elles sont peut-être très bien, mais je ne les ai jamais utilisées. Probablement parce qu’elles ne sont pas aussi faciles à intégrer avec une application Shiny. Il faudrait que je construise moi-même un package similaire à auth0
pour les interfacer avec Shiny.
En revanche, j’ai beaucoup utilisé AWS Cognito pour des clients qui hébergent leur application sur AWS.
Et si je devais résumer mon expérience: fuiyez. C’est une plaie.
- L’interface utilisateur est à peine personnalisable. Comparé à Auth0, c’est le jour et la nuit.
- Bien que ce soit un service AWS, il ne s’intègre pas si bien avec leurs autres services. Par exemple, si vous répliquez votre application Shiny sur deux régions AWS, vous allez devoir gérer deux bases de données Cognito indépendantes, sans possibilité de les synchroniser.
- Il a moins de fonctionnalités, la documentation est moins bonne, etc.
- J’aime pas.
Comparé à Auth0, je ne vois aucune bonne raison d’utiliser Cognito.
Bon, après cette petite appartée…
Comment implémenter Auth0 dans votre application Shiny ?
La suite … après la pub.
3. Ajouter un portail d’authentification Auth0 à votre application Shiny
Vous êtes toujours là ?
Bravo pour votre perséverance ! Malgré un début un peu théorique et l’absence d’applications concrètes, c’était important de poser les bases.
Maintenant, on va enfin ajouter un système d’authentification à votre application.
Commençons par créer une application basique. Je crée deux fichiers :
fluidPage(
titlePanel("Application Basique")
)
function(input, output, session) {
}
Je ne vous ai pas menti: c’est une application basique.
Maintenant, protégeons le contenu de cette application avec un portail d’authentification.
Spoiler: À la fin de cette section, vous aurez 6 fichiers :
ui <- fluidPage(
titlePanel("Application Basique")
)
auth0::auth0_ui(ui)
server <- function(input, output, session) {
}
auth0::auth0_server(server)
name: myApp
remote_url: ""
auth0_config:
api_url: !expr paste0("https://", Sys.getenv("AUTH0_TENANT"), ".", Sys.getenv("AUTH0_REGION"), ".auth0.com")
credentials:
key: !expr Sys.getenv("AUTH0_CLIENT_ID")
secret: !expr Sys.getenv("AUTH0_CLIENT_SECRET")
AUTH0_TENANT=datachamp-article-auth0
AUTH0_REGION=eu
AUTH0_CLIENT_ID=K2PUnHPBhyxvhfGs5to0FXfxeBIV9bBm
AUTH0_CLIENT_SECRET=mysupersecret
.Renviron
options(shiny.port = 4050)
Pas de panique, je vais tout expliquer.
3.1. Créer et configurer un compte Auth0
La première étape ne se réalise pas dans R. Vous devez d’abord configurer votre compte Auth0.
Créer votre premier Tenant
Allez sur https://auth0.com/ et créez votre compte.
À la fin de la création de compte, vous serez invité à create your first Tenant.
Vous pouvez penser au Tenant comme une sorte de sous-compte:
- Vous définissez un ID. Je vais nommer le mien
datachamp-article-auth0
. - Vous choisissez une Region. Je vais créer le mien dans la région EU, parce que c’est là où je vis.
- Vous choisissez un Environment Tag : Development, Staging, ou Production. C’est surtout un moyen d’organiser vos environnements. Sauf si vous avez un abonnement payant, auquel cas les Tenants de Production ont des limites de taux plus élevées.
Le Tenant contiendra votre base de données utilisateurs, la configuration des mécanismes d’authentification, la personnalisation du portail d’authentification, etc.
En général, on crée un Tenant par application. Si vous avez la même base d’utilisateurs sur plusieurs applications, vous pourriez envisager d’avoir un Tenant commun pour ces applications.
Une fois le Tenant créé, Auth0 vous fera une visite guidée. Pour être honnête, ce n’est pas très utile. Ils vous demanderont aussi d’indiquer le tech stack que vous utilisez. Vous rentrez “Shiny”, et vous remarquerez à nouveau à quel point la communauté R est méprisée et ignorée.
…
Bref.
Créer une nouvelle Application
Depuis la barre latérale, allez dans Applications > Applications. Là, vous devriez voir une Default App. Cliquez dessus, allez dans Settings, défilez jusqu’à la Danger Zone en bas, et supprimez-la. Nous allons en créer une nouvelle à partir de zéro.
Créez une nouvelle Application, et choisissez la configuration suivante :
- Nom : Entrez le nom de votre application. Pour moi c’est “DataChamp’ Article Auth0”.
- Type d’application : Une application Shiny est une Regular Web Application.
Vous arriverez sur l’onglet Quickstart de votre nouvelle Application. Et ils vous demanderont la technologie que vous utilisez pour le projet.
Et…
Bon.
Continuons.
Configurer les paramètres de l’Application
Allons dans l’onglet Settings et passons en revue les différents paramètres :
- Name: C’est le nom que vous avez déja choisi mais vous pouvez le changer à tout moment.
- Domain: Le domaine est lié à l’ID de votre Tenant, donc vous ne pouvez pas le changer. Le format est
{tenant_id}.{region}.auth0.com
. Votre portail d’authentification sera hébergé sur cette URL, donc gardez à l’esprit que vos utilisateurs verront votre domaine. - Client ID and Client Secret: Ils seront utilisés plus tard lors de la configuration de l’application Shiny. Pas besoin de les noter, mais sachez qu’ils sont disponibles ici.
Défilez un peu jusqu’à trouver la section Application URIs. Vous devez ajouter les URLs où votre application sera hébergée sous les trois formes suivantes :
- Allowed Callback URLs
- Allowed Logout URLs
- Allowed Web Origins
Auth0 veut s’assurer que votre portail d’authentification sera utilisé uniquement pour vos applications, et que quelqu’un qui trouverait votre Client Secret ne pourra pas utiliser votre portail d’authentification pour son application. C’est un peu lourd … mais voyez ça comme une sécurité supplémentaire.
En fait, vous devez entrer deux URLs dans chaque champ. Je vais ajouter :
https://shiny.datachamp.fr/datachamp/posts/auth0
: C’est l’adresse où je vais héberger mon application.http://localhost:4050
: C’est pour quand je vais travailler sur mon application. Comme Shiny démarre toujours un serveur local sur votre ordinateur, vous devez aussi mettre cette adresse dans la liste des URLs autorisées. Ici, j’ai choisi le numéro de port 4050, mais vous pouvez choisir n’importe quel chiffre entre 1000 et 9999.
Plus tard, dans Shiny, j’ajouterai une option pour que le serveur local Shiny utilise toujours le port 4050, sinon il en choisit un au hasard.
Si vous ne connaissez pas la future URL de votre application, pas de problème. Entrez simplement l’adresse localhost, et vous compléterez le reste plus tard.
Vous pouvez copier/coller les mêmes URLs dans les deux premiers champs de texte. Pour le troisième champ, Allowed Web Origins, il faut rentrer le début de l’URL (i.e. https://shiny.datachamp.fr), et non l’adresse complète.
Au final, vous devriez avoir :
Vous pouvez laisser le reste des options de configuration telles quelles. Mais n’oubliez pas de cliquer sur Save changes en bas de la page.
Configurer les méthodes d’authentification
Ensuite, allez dans l’onglet Connections. C’est là que vous pouvez choisir la facon dont les utilisateurs peuvent se connecter à votre application. Il peut s’agir de :
- Username/Password: Vous vous connectez avec un nom d’utilisateur et un mot de passe.
- Social logins: Vous vous connectez via un fournisseur d’identité public, comme Google, Microsoft, Facebook, Github, etc.
- Enterprise: Vous vous connectez via votre propre service d’identité en utilisant OpenID Connect, SAML, etc. Généralement pour implémenter un SSO (Single Sign-On).
- Passwordless: Ici il n’y a pas de mot de passe. Pour chaque connexion, l’utilisateur recevra un mot de passe temporaire par SMS ou email.
Pour cet article, nous allons uniquement présenter l’authentification par Username/Password, donc vous pouvez désactiver la connexion via google-oauth2
qui existe par défaut. Vous pouvez également supprimer complètement cette méthode de connexion en allant dans Authentication / Social dans la barre latérale, et en supprimant google-oauth2
.
Paramètres généraux
Pour conclure cette section je vais vous présenter certains paramètres généraux (c.à.d. non spécifiques à l’application). Je vais vous montrer les options qui me parraissent les plus importantes, mais n’hésitez pas à explorer le reste de l’interface Auth0 pour découvrir le reste.
Allez dans Settings dans la barre latérale. Depuis l’onglet General, vous pouvez configurer les options qui amélioreront l’apparence de votre futur portail d’authentification :
- Friendly Name: C’est le nom qui apparaîtra à la place du nom du Tenant. Par exemple, “Data Champ’” à la place de “datachamp-article-auth0”.
- Logo URL: Si votre logo est publiquement accessible, rentrez l’URL ici.
- Environnement Tag: Vous avez déjà choisi l’environnement lors de la création du Tenant. Vous pouvez toujours le changer ici.
- Languages: Vous pouvez utiliser plusieurs langues pour votre portail d’authentification. Une fois activé, le portail changera de langue en fonction des paramètres du navigateur de l’utilisateur.
Pour l’instant, nous avons parcouru tout ce dont nous avions besoin pour la configuration initiale.
Prochaine étape: Shiny.
3.2. Connecter Shiny à votre Application Auth0
Créer des fichiers de configuration
Créez un nouveau fichier nommé _auth0.yml
à la racine de votre projet :
name: myApp
remote_url: ""
auth0_config:
api_url: !expr paste0("https://", Sys.getenv("AUTH0_TENANT"), ".", Sys.getenv("AUTH0_REGION"), ".auth0.com")
credentials:
key: !expr Sys.getenv("AUTH0_CLIENT_ID")
secret: !expr Sys.getenv("AUTH0_CLIENT_SECRET")
Remplacez name par le nom de votre Application et assurez-vous qu’il y ait une ligne vide à la fin du fichier.
Ce fichier contiendra le Client ID et le Client Secret que nous avons vu précédemment lors de la configuration de l’Application Auth0. Cependant, les valeurs ne doivent pas être écrites directement dans le fichier.
Pourquoi ?
Parce que. Pour pouvoir gérer de multiple environnements, et pour s’assurer que leurs secrets ne sont pas divulgués.
Gestion des variables d’environnement
Le fichier _auth0.yml
sera envoyé à vos collègues, ou sur votre repository Github. Il pourrait être publié à un moment donné. En bref: vous ne devriez jamais écrire un mot de passe dans un fichier qui sera envoyé à d’autres personnes. Et le Client Secret EST un mot de passe.
Concernant les environnements: vous pourriez avoir un Tenant Auth0 pour le développement, un pour le staging, et un pour la production. Pour chaque environnement, les valeurs seront différentes. Plutôt que de modifier manuellement les valeurs à chaque fois, il vaut mieux les écrire dans un fichier qui est fait pour configurer l’environnement R.
Créez un fichier .Renviron
à la racine de votre projet, avec :
AUTH0_TENANT=datachamp-article-auth0
AUTH0_REGION=eu
AUTH0_CLIENT_ID=K2PUnHPBhyxvhfGs5to0FXfxeBIV9bBm
AUTH0_CLIENT_SECRET=mysupersecret
Ce fichier .Renviron
ne devrait jamais être publié sur un repository Git (ou envoyé à d’autres personnes). Les valeurs qu’il contient pourraient également changer d’un environnement à l’autre.
Si vous utilisez Git, n’oubliez pas de l’ajouter à votre .gitignore
:
.Renviron
Rappel: vous pouvez trouver le Client ID et le Client Secret dans votre compte Auth0. Allez dans Applications > Applications, sélectionnez votre Application, et cliquez sur Settings:
Une fois que cela est fait, redémarrez votre session R pour que les variables d’environnement soient prises en compte. Lorsque vous exécutez Sys.getenv("AUTH0_TENANT")
dans votre console, il devrait afficher la valeur correspondante de votre fichier .Renviron
. Si ce n’est pas le cas, assurez-vous que votre session démarre bien dans le répertoire de travail de votre projet, où se trouve le fichier .Renviron
.
Pour plus d’informations sur le fonctionnement du fichier .Renviron
, vous pouvez lire cet article. C’est un outil très utile lorsque vous hébergez des applications Shiny en production.
Configurer le numéro de port
Quand nous avons ajouté les URLs à la configuration de l’Application Auth0, nous avions décidé d’autoriser http://localhost:4050
.
Maintenant, il faut préciser à Shiny de toujours exécuter le serveur local de votre application sur ce numéro de port. Pour ce faire, il vous suffit simplement d’ajouter ce bout de code R :
options(shiny.port = 4050)
Je vous recommande de mettre cette option dans un fichier .Rprofile
. De la même façon que le fichier .Renviron
, ce fichier contiendra des instructions R qui seront toujours exécutées lorsque vous démarrerez une session R.
Vous devriez déjà avoir un fichier .Rprofile
si vous utilisez renv
(ce que je vous recommande de faire: lisez-en plus ici).
options(shiny.port = 4050)
Au fait… Le numéro de port pourrait également être une variable d’environnement et être défini dans le fichier .Renviron
, auquel cas vous devriez appeler options(shiny.port = Sys.getenv("SHINY_PORT"))
.
On continue.
Ajouter Auth0 à votre application Shiny
Il est maintenant temps d’ajouter le package auth0
à l’application. Voici les modifications nécessaires :
ui <- fluidPage(
titlePanel("Basic App")
)
auth0::auth0_ui(ui)
server <- function(input, output, session) {
}
auth0::auth0_server(server)
C’est tout?
Eh oui. C’est tout.
Exécutez l’application, et vous devriez voir le portail d’authentification :
Vous verrez que le portail d’authentification doit être personnalisé. Le texte est un peu bizarre, les couleurs ne vont probablement pas correspondre à votre charte graphique, …. Pas de soucis, tout est personnalisable !
3.3. Troubleshooting
Des problèmes ?
There is no package called ‘auth0’
Cela signifie que vous avez oublié d’installer le package auth0
. Installez-le comme ceci :
install.packages("auth0")
We can’t connect to the server at ..auth0.com.
Cela signifie que vous avez été redirigé vers le portail d’authentification. Sauf qu’en fait, il vous a redirigé vers l’adresse https://..auth0.com.
La raison la plus probable est que vos variables d’environnement sont vides. Soit elles n’existent pas, soit elles ne sont pas chargées correctement dans la session. Pour en savoir plus sur la façon de résoudre ce problème, lisez cet article sur .Renviron.
Callback URL mismatch
Vous remarquerez que le message d’erreur est en dessous de l’image: “The provided redirect_uri is not in the list of allowed callback URLs.”
Si cela arrive, regardez l’URL de cette page d’erreur. Elle contient votre URL de callback (dans un format URL encodé). Par exemple, voici l’URL que je vois :
https://datachamp-article-auth0.eu.auth0.com/authorize? \
client_id=K2PUnHPBhyxvhfGs5to0FXfxeBIV9bBm& \
scope=openid%20profile& \
redirect_uri=http%3A%2F%2Flocalhost%3A3726& \
response_type=code& \
state=5hVXwbxP2z
C’est un peu difficile à lire car chaque caractère non-ASCII est encodé, mais en bref, le redirect_uri
est configuré pour être http://localhost:3726
.
Cela signifie que Shiny à utilisé un mauvais numéro de port (qui est aléatoire par défaut).
Utilisez options(shiny.port = 4050)
, ou tout autre numéro de port que vous avez configuré dans les URLs de rappel de l’Application Auth0.
4. Améliorer votre nouveau portail d’authentification
C’est bon, vous êtes prêt.
Après avoir démarré votre application Shiny, utilisez l’écran de connexion Auth0 pour créer votre compte.
Vous vous demandez peut-être pourquoi vous voyez “Authorize App” s’afficher après avoir créé votre compte ? Vous pourrez en lire plus à ce sujet dans la section : Comment supprimer l’écran “Authorize App” après l’inscription sur Auth0
Pour l’instant, je vais vous montrer comment améliorer votre portail d’authentification pour les besoins les plus basiques.
4.1. Ajouter un bouton de déconnexion
La première chose que vous pourriez vous demander est… comment se déconnecter ?
En fait, à chaque fois que vous démarrez l’application, elle vous connecte automatiquement.
Heureusement, ajouter un bouton de déconnexion à votre application est très simple grâce au package auth0
. Il vous suffit d’ajouter une ligne à votre fichier ui.R
:
ui <- fluidPage(
titlePanel("Basic App"),
auth0::logoutButton()
)
auth0::auth0_ui(ui)
Vous n’avez même pas besoin de faire quoi que ce soit dans le fichier server.R
tant que vous n’avez qu’un seul bouton de déconnexion. Si vous voulez en avoir plusieurs, je vous invite à consulter la documentation de la fonction auth0::logoutButton()
.
4.2. Accéder aux informations utilisateur après l’authentification
Vous voulez savoir qui sont les utilisateurs connectés à votre application ? Ca peut être très utile lorsque vous voulez que l’application ait un comportement spécifique pour certains utilisateurs.
Les informations de l’utilisateur sont automatiquement stockées dans l’objet session$userData$auth0_info
.
Mais, pour y avoir accès, vous devez faire des petites modifications à notre appli :
- Créer un fichier
global.R
et définir la variableauth0_info
- Passer la variable
auth0_info
nouvellement créée aux fonctionsauth0::auth0_ui
etauth0::auth0_server
Voici les fichiers :
ui <- fluidPage(
titlePanel("Basic App"),
verbatimTextOutput("user_info"),
auth0::logoutButton()
)
auth0::auth0_ui(ui, info = auth0_info)
server <- function(input, output, session) {
output$user_info <- renderPrint({
session$userData$auth0_info
})
}
auth0::auth0_server(server, info = auth0_info)
auth0_info <- auth0::auth0_info()
Et le résultat :
C’est une liste avec 5 éléments :
- Le
sub
est l’ID utilisateur Auth0. Si vous vous connectez à votre interface d’administration Auth0, allez dans User Management / Users, et sélectionnez l’utilisateur, vous le verrez tel que:
- Le
nickname
est probablement la partie gauche de l’adresse email, généré automatiquement. Notez que vous pouvez aussi demander aux utilisateurs d’entrer un nom d’utilisateur lors de l’inscription. - Le
name
est l’adresse email. - La
picture
est automatiquement récupérée depuis Gravatar en fonction de l’adresse email de l’utilisateur. - Le
updated_at
est … c’est explicite.
À partir de ces informations, vous pouvez personnaliser un message de bienvenue pour vos utilisateurs.
Toutefois, ce n’est pas beaucoup d’informations… On pourrait penser que si vous voulez stocker plus de données, vous allez devoir construire votre propre base de données et stocker des données associées à l’ID utilisateur Auth0.
C’est une possibilité.
Mais … nous verrons plus tard dans l’article que vous pouvez aussi utiliser Auth0 comme “base de données” pour stocker des informations sur les utilisateurs (cf. 5.5. Comment stocker et accéder aux données utilisateur Auth0 dans Shiny).
4.3. Un mot sur la sécurité
Avant de continuer…
Je veux rapidement revenir sur un point évoqué précédemment, concernant les deux méthodes d’authentification principales, c.à.d. d’implémenter l’authentification au niveau du serveur web ou au niveau de l’application Shiny.
Ici, nous la configurons au niveau de l’application Shiny. Notez que nous pourrions aussi configurer Auth0 au niveau du serveur web, mais ce n’est pas l’objet de ce tutoriel.
L’avantage de cette méthode est qu’elle est super facile à mettre en place :
- La configuration sur Auth0 : vous avez juste à créer un compte et ajouter votre URL.
- La configuration sur Shiny : vous avez juste à wrap les objets
ui
etserver
avec des fonctions du packageauth0
.
Ce ne serait pas aussi facile au niveau du serveur web.
Cependant, l’inconvénient de le faire dans Shiny est que vous devez être un peu plus prudent lorsque vous codez votre application.
Avez-vous remarqué comment le package auth0
fonctionne ?
- D’abord, l’application Shiny commence à se charger.
- Ensuite, l’écran devient gris et vous êtes redirigé vers le portail d’authentification Auth0.
- Vous vous connectez.
- Vous êtes redirigé à nouveau vers l’application Shiny et l’URL a été complétée avec une sorte de code :
?code=gPuf8Letc...
Ce sur quoi je veux attirer votre attention, ce sont les deux premières étapes : l’application Shiny commence à se charger avant que vous ne soyez connecté. Et c’est quelque chose qui demande de la prudence.
Tout ce qui est dans l’UI est protégé.
Cela vient de la façon dont auth0::auth0_ui()
fonctionne. Avant même de charger l’UI, il va vérifier le code dans l’URL. Si le code n’est pas présent ou incorrect, alors il remplace le contenu de l’UI par :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="application/shiny-singletons"></script>
<script type="application/html-dependencies">jquery[3.6.0];shiny-css[1.9.1];shiny-busy-indicators[1.9.1];shiny-javascript[1.9.1]</script>
<script src="jquery-3.6.0/jquery.min.js"></script>
<link href="shiny-css-1.9.1/shiny.min.css" rel="stylesheet" />
<link href="shiny-busy-indicators-1.9.1/busy-indicators.css" rel="stylesheet" />
<script src="shiny-javascript-1.9.1/shiny.min.js"></script>
</head>
<body>
<script>location.replace("https://datachamp-article-auth0.eu.auth0.com/authorize?client_id=K2PUnHPBhyxvhfGs5to0FXfxeBIV9bBm&scope=openid%20profile&redirect_uri=http%3A%2F%2Flocalhost%3A4050&response_type=code&state=ye75t9rCne");</script>
</body>
</html>
Pas de panique !
C’est juste le code HTML qui est chargé avant que l’utilisateur ne soit connecté. La majorité de ce code sert à charger des fichiers CSS et JS.
Ensuite, dans le body
, il y a une seule ligne de JavaScript, qui redirige vers le portail d’authentification Auth0.
L’UI de votre application n’est jamais chargée, il n’y a donc aucun risque de fuite d’information.
Mais… tout ce qui est dans le serveur n’est pas (forcément) protégé !
Tous les outputs sont protégés, puisqu’ils dépendent de leur équivalent UI pour se charger. C’est a dire que pour uiOutput
, plotOutput
, tableOutput
, ou tout autre output Shiny, il n’y a rien à craindre.
Cependant, si vous avez des observers, il peuvent eventuellement être exécutés sans que l’utilisateur ne soit connecté.
Voici un exemple :
ui <- fluidPage(
titlePanel("Basic App"),
verbatimTextOutput("user_info"),
auth0::logoutButton()
)
auth0::auth0_ui(ui, info = auth0_info)
server <- function(input, output, session) {
output$user_info <- renderPrint({
session$userData$auth0_info
})
observe({
print("test")
})
}
auth0::auth0_server(server, info = auth0_info)
auth0_info <- auth0::auth0_info()
J’ai simplement ajouté une instruction observe(print("test"))
dans le fichier server.R
.
Si vous essayez cette application, vous remarquerez que "test"
apparaît deux fois :
> shiny::runApp()
Loading required package: shiny
Listening on http://127.0.0.1:4050
Browsing http://127.0.0.1:4050
[1] "test"
[1] "test"
- La première fois avant d’être connecté
- La deuxième fois après être connecté
Cela montre que du code Shiny a été exécuté avant que l’utilisateur ne soit connecté.
Cela ne posera pas de problème dans la majorité des cas.
Mais selon votre application, ça pourrait devenir problématique.
Même en utilisant un outil sécurisé comme Auth0, vous êtes toujours responsable du code que vous écrivez et devez être conscient des vulnérabilités potentielles.
Comment pouvez-vous vous assurer que ce code n’est jamais exécuté pour un utilisateur non autorisé ?
Eh bien, pour vérifier si l’utilisateur est connecté, utilisez l’objet session$userData$auth0_info
dont nous avons parlé dans la section précédente. Si l’utilisateur n’est pas connecté, l’objet sera NULL
.
Vous pouvez simplement utiliser la fonction req()
(consultez la help page si vous ne connaissez pas cette fonction) pour bloquer l’exécution du code si l’objet est NULL
:
ui <- fluidPage(
titlePanel("Basic App"),
verbatimTextOutput("user_info"),
auth0::logoutButton()
)
auth0::auth0_ui(ui, info = auth0_info)
server <- function(input, output, session) {
output$user_info <- renderPrint({
session$userData$auth0_info
})
observe({
req(session$userData$auth0_info)
print("test")
})
}
auth0::auth0_server(server, info = auth0_info)
auth0_info <- auth0::auth0_info()
Maintenant, un seul "test"
apparaît :
> shiny::runApp()
Loading required package: shiny
Listening on http://127.0.0.1:4050
Browsing http://127.0.0.1:4050
[1] "test"
Maintenant, vous comprenez mieux pourquoi la première méthode, où l’authentification se fait avant que les requêtes n’atteignent le serveur Shiny, est plus sécurisée.
Ici, nous avons opté pour la méthode qui est plus facile à implémenter. La contrepartie est que vous devez faire attention à la sécurité dans votre code Shiny.
Bien, maintenant que les trucs ennuyeux-mais-importants sur la sécurité sont terminés, parlons design !
4.4. Redesigner le portail d’authentification
Que pensez-vous du portail d’authentification par défaut ?
Franchement, c’est pas si mal.
Mais il n’a pas beaucoup de personnalité.
Retournez dans l’interface d’administration Auth0, et allez dans Branding > Universal Login. Ici, vous pouvez :
- Sélectionner un logo
- Mettre à jour la couleur principale
- Mettre à jour la couleur de fond
Ne vous inquiétez pas, vous aurez d’autres options.
Mais…
Pour info, c’est déjà plus que ce que vous pouvez faire avec AWS Cognito 🤡
Après avoir édité quelques options sur Auth0, j’obtiens :
… et on retrouve déjà l’ambiance de la marque Data Champ’ !
Maintenant, cliquez sur Customization Options. C’est là que tout ce qui concerne le design peut être modifié :
- Je mets à jour les autres couleurs pour correspondre à la marque Data Champ’
- Je reprends la police que nous utilisons sur le site web
- J’augmente légèrement la taille de la police
- Et… c’est à peu près tout en fait.
Vous avez peut-être remarqué le logo Auth0 en bas. C’est lié à l’utilisation de la version gratuite. Si vous voulez le supprimer, vous allez devoir ouvrir votre porte monnaie.
4.5. Personnaliser le texte
Maintenant, mettons à jour le texte affiché dans le portail d’authentification. Retournez dans Branding > Universal Login et cliquez sur Advanced Options.
La première option que vous verrez concerne “Universal Login” vs “Classic Login”. Pour faire court, le “Classic Login” est leur ancienne façon de faire les choses.
Cliquez sur l’onglet Custom Text. C’est là que vous pouvez personnaliser chaque bout de texte de l’interface.
En haut, vous pouvez choisir :
- Language : Cela personnalisera le texte pour une langue spécifique. Sachant que vous pouvez activer ou désactiver des langues spécifiques dans les paramètres généraux.
- Prompt : Cela correspond à l’étape du processus d’authentification : connexion, inscription, saisie du code 2FA, récupération de mot de passe, etc.
Vous voyez maintenant pourquoi vous ne voulez PAS construire votre propre portail ? Ca ferait beaucoup de pages à créer et gérer.
Heureusement, nous n’avons pas besoin de couvrir tous les cas pour notre application démo. Je ne vais personnaliser que les prompts suivants : login, signup, et reset-password. Notez que reset-password a plusieurs écrans.
Vous remarquerez que la plupart des champs sont pré-remplis en utilisant des variables. Compte tenu du nombre de prompts et d’écrans, je recommande d’utiliser des variables autant que possible, pour ne pas avoir à vous répéter.
Pour chaque prompt, au lieu d’éditer les champs de texte, vous pouvez cliquer sur l’onglet Raw JSON en haut. Cela vous permet de sauvegarder vos personnalisations et de les ajouter à un repository Git, pour mieux suivre les changements que vous avez apportés au portail.
À ce stade, je recommande de parcourir chaque écran possible de votre portail d’authentification par vous-même, c’est-à-dire essayer de vous connecter, de vous inscrire, d’oublier votre mot de passe, …, et de regarder chaque page attentivement pour voir ce qui doit être personnalisé.
C’est beaucoup de travail, mais cela vous permettra de créer une image de marque cohérente pour votre application.
Par exemple, quand vous essayez de réinitialiser votre mot de passe, Auth0 vous enverra un email. Et cet email peut être personnalisé aussi.
4.6. Personnaliser les emails
Les emails par défaut sont corrects. Voici à quoi ressemblera l’email de Réinitialisation de mot de passe par défaut avec les personnalisations génériques de marque que nous avons déjà implémentées:
Mais vous pouvez quand même personnaliser leur design et leur contenu.
Pour ce faire, depuis la barre latérale, cliquez sur Branding > Email Templates.
Et…
En gros, Auth0 n’enverra des emails en votre nom qu’à des fins de test.
Une fois que vous mettez votre application en production, vous devrez indiquer un fournisseur d’email. Je couvre cette partie dans le chapitre 5.4. Comment utiliser les emails en production.
En attendant, nous pouvons toujours nous amuser avec les templates, mais sachez qu’ils ne s’activeront pas tant que vous serez en mode sandbox.
Pour en revenir aux modèles d’email :
Dans la section Email Templates, dans le menu déroulant Template en haut, choisissez Change Password (Link). Cela correspond à l’email que l’utilisateur recevra lorsqu’il essaiera de réinitialiser son mot de passe. Vous pouvez personnaliser :
- From : l’adresse email
- Subject : l’objet de l’email
- URL to redirect to : l’URL de redirection après validation du nouveau mot de passe
- URL Lifetime : la durée de vie de l’URL, pour faire expirer l’URL après quelques jours
Et ensuite…
Vous pouvez personnaliser tout le contenu HTML de l’email. Si vous voulez seulement personnaliser certains éléments, vous pouvez les chercher dans le modèle HTML et les remplacer par des phrases personnalisées.
Cependant, vous pourriez aussi entièrement refaire le contenu HTML de zéro.
Voici un exemple où j’ai supprimé du texte et les couleurs :
Et un autre exemple où j’ai tout refait à partir de zéro :
Vous pensez que c’est trop fastidieux à faire ?
J’ai juste copié/collé le modèle par défaut dans “ChatGPT 4o with canvas”, ajouté un PDF avec la charte graphique de Data Champ’, et lui ai demandé de créer un nouveau design plus proche de la marque Data Champ’.
N’hésitez pas à personnaliser autant de templates d’email que vous le souhaitez.
A présent, vous avez un portail d’authentification sécurisé, fonctionnel, et personnalisé. Nous avons couvert tous les éléments essentiels dont vous avez besoin pour commencer.
La prochaine section de l’article couvre certains cas d’utilisation spécifiques, alors n’hésitez pas à sauter les sous-sections qui ne s’appliquent pas à vous.
Par ailleurs, si vous voulez faire quelque chose que nous n’avons pas couvert dans l’article, faites-le nous savoir pour que nous puissions ajouter une section à ce sujet!
5. Utilisation avancée d’Auth0 dans Shiny
5.1. Comment supprimer l’écran ‘Autoriser l’application’ après l’inscription sur Auth0 ?
Par défaut, lorsqu’un nouvel utilisateur s’inscrit, Auth0 affiche un écran ‘Authorize App’ :
Cela peut vous surprendre car ce n’est pas quelque chose que vous rencontrez lorsque vous créez un compte sur la plupart des services sur internet.
En général, vous remplissez votre adresse email, votre mot de passe, cliquez sur “Créer un compte”, et c’est tout. On ne vous demande pas si l’application pour laquelle vous créez un compte est autorisée à accéder à votre compte. Étrange, non ?
En fait, cela se produit parce que vous exécutez l’application en local, dans votre environnement de développement.
Auth0 vous perçoit alors comme une application tierce, et l’application demande l’autorisation d’accéder aux informations de l’utilisateur (nouvellement créé).
Vous pouvez en lire plus à ce sujet sur les forums Auth0 : What is the Authorize App screen during signup?.
Cette étape n’apparaîtra pas lorsque votre application sera déployée en production.
5.2. Comment désactiver les inscriptions dans Auth0 ?
Un besoin courant pour les applications privées est de désactiver les inscriptions. Par exemple, si vous souhaitez ajouter un utilisateur manuellement après avoir signé un contrat avec eux.
N.B. : Si ce que vous voulez c’est autoriser les inscriptions uniquement depuis des domaines spécifiques (par exemple, n’autoriser que les employés avec @datachamp.fr à créer un compte), sautez à la section suivante : 5.3. Comment n’autoriser que les inscriptions depuis un domaine spécifique ?
Désactiver les inscriptions est très simple :
- Allez dans Authentication > Database
- Cliquez sur le lien Username-Password-Authentication
- Faites défiler jusqu’en bas de la page et activez le bouton Disable Sign Ups.
P.S. : Sur cette capture d’écran, je ne l’ai pas activé, donc n’importe qui pourra créer un compte.
5.3. Comment n’autoriser que les inscriptions depuis un domaine spécifique ?
Cette partie est un peu plus complexe, mais vous verrez qu’Auth0 vous facilite vraiment la tâche.
Allez dans Actions > Library.
Quelques points sur Actions avant d’aller plus loin : une Action est un morceau de code qui s’exécutera chaque fois qu’un événement se produit. Vous pouvez avoir des actions :
- Avant qu’un utilisateur ne soit créé (c’est ce que nous voulons)
- Après qu’un utilisateur soit créé
- Après qu’un utilisateur demande à réinitialiser son mot de passe
- Après qu’un utilisateur se connecte
- Etc.
Dans notre cas, nous voulons vérifier le domaine de l’adresse email juste avant que l’utilisateur soit créé. Et si le domaine ne correspond pas au nôtre, alors nous bloquons la création du compte.
Notez que vous pouvez écrire n’importe quelle Action personnalisée. La seule exigence est de l’écrire en JavaScript. Heureusement, nous n’aurons pas besoin d’écrire notre propre code puisque nous pouvons utiliser des modèles d’actionsexistants.
Cliquez sur Create Action > Use a Marketplace Integration.
Dans la barre de recherche, tapez Domain pour trouver l’action Domain Based Registration.
Sélectionnez-la, puis cliquez sur Add Integration. Ensuite, il vous suffit de la configurer avec les paramètres suivants :
- Approved Domains : Entrez la liste des domaines approuvés, séparés par des virgules. Par exemple :
datachamp.fr
- Error : C’est le message d’erreur que vous verrez dans les logs quand un utilisateur essaie de s’inscrire avec une adresse email non autorisée.
- User Error Message : C’est le message d’erreur que les utilisateurs verront quand ils essaient de s’inscrire avec une adresse email non autorisée.
Une fois que c’est fait, vous devez configurer l’Action pour qu’elle soit déclenchée après qu’un utilisateur essaie de créer un compte.
Allez dans Actions > Triggers et choisissez pre-user-registration
.
Selectionnez et faites glisser votre nouvelle Action Domain Based Registration juste entre Start et Complete :
Cliquez sur Apply.
Maintenant, vos changements sont prêts. Vous pouvez essayer de vous inscrire avec une adresse email non autorisée :
Il y a cependant une limitation… Que se passe-t-il si un utilisateur triche et utilise une fausse adresse email avec le bon domaine ?
Rien n’empêche l’utilisateur d’utiliser [email protected]
, de créer le compte et d’accéder à l’application. Vous avez donc besoin d’un mécanisme supplémentaire pour forcer l’utilisateur à confirmer son adresse email avant de lui donner accès.
Nous couvrons cela dans la section 5.6. Comment vérifier si un utilisateur a validé son adresse email ?.
5.4. Comment utiliser les emails en production ?
Si vous voulez utiliser les Email Templates, ou avoir le contrôle du processus d’envoi d’email, vous devez renseigner un fournisseur d’email personnalisé.
Dans cette section, je vais vous montrer une façon de le faire. Mais gardez à l’esprit que vous pouvez utiliser n’importe quel fournisseur d’email, ou vous pourriez même construire votre propre serveur d’email.
Dans mon cas, je travaille souvent avec Mailjet, donc je vais l’utiliser comme fournisseur pour cet exemple.
D’abord, créez votre compte Mailjet.
Une fois créé, allez dans le menu API et créez une clé API.
De retour sur Auth0, allez dans Branding > Email Provider.
Cochez la case Use my own email provider, puis SMTP Provider. Remplissez le formulaire avec les valeurs suivantes :
- From : Ecrivez l’adresse email depuis laquelle vous voulez envoyer les emails, qui, par défaut, devrait être la même que celle que vous avez utilisée pour créer votre compte Mailjet.
- Host : Ecrivez
in-v3.mailjet.com
- Port : 587
- Username : Ecrivez la clé API Mailjet
- Password : Ecrivez la clé secrète Mailjet
Si vous cliquez sur Send Test Email, cela pourrait ne pas fonctionner immédiatement.
Mailjet doit vérifier que vous êtes autorisé à envoyer des emails avec l’adresse email que vous avez choisie.
Retournez sur Mailjet et dans vos Account Settings, puis Domains and senders.
Les adresses non vérifiées seront affichées sur cette page. Vous pouvez les valider en demandant à Mailjet d’envoyer un email de confirmation, puis en confirmant votre adresse email.
5.5. Comment stocker et accéder aux données utilisateur Auth0 dans Shiny ?
Nous avons déjà vu comment accéder aux informations utilisateur dans 4.2. Accéder aux informations utilisateur après l’authentification.
Mais les informations accessibles de cette façon sont assez limitées :
Vous pourriez vouloir stocker plus d’informations sur l’utilisateur, comme :
- User preferences : Pour stocker des paramètres correspondant aux préférences de l’utilisateur comme la langue, les préférences de notification, le thème clair vs sombre.
- Application data : Pour garder une trace des informations spécifiques à l’utilisateur, comme les catégories favorites ou les éléments récemment consultés.
- Checks : Pour enregistrer si l’utilisateur a terminé un tutoriel, accepté les conditions d’utilisation, etc.
- Cache : Pour mettre en cache tout calcul gourmand en ressources qui est spécifique à un utilisateur.
Puisque vous avez accès au sub
, ou ID Auth0, vous pourriez créer votre propre base de données et lier les données de l’utilisateur à cet ID. Mais… ne serait-ce pas génial si vous pouviez ne pas avoir à gérer une base de données et tout stocker chez Auth0 ? Nous pouvons faire cela avec User Metadata et App Metadata :
Depuis l’interface Auth0, allez dans User Management > Users, et cliquez sur n’importe quel utilisateur dans la liste. Sur l’onglet Details (celui ouvert par défaut), faites défiler jusqu’à voir :
- User Metadata : utilisé pour stocker les attributs utilisateur comme les préférences. Les utilisateurs peuvent potentiellement accéder à ce fichier*.
- App Metadata : utilisé pour stocker les informations utilisateur comme les permissions ou tout ce que les utilisateurs ne devraient pas pouvoir consulter.
Auth0 n’est qu’une façon (pratique) de stocker ces données. Vous pourriez configurer votre propre base de données, ou stocker les données sur la machine du client (en utilisant des cookies). Si vous préférez utiliser des cookies, pensez à ne pas stocker de données confidentielles ou des données qui ne devraient pas être accessibles par l’utilisateur (comme les droits d’accès).
Si les données que vous devez stocker sont confidentielles, alors gardez à l’esprit qu’Auth0 est un service tiers, et c’est à vous de décider si vous leur faites confiance avec ces données. En règle générale, je vous recommande d’héberger les données confidentielles dans un environnement que vous contrôlez et en qui vous avez confiance.
Enfin, il y a une limitation de 16 Mo. Cela devrait être suffisant, car vous n’êtes pas censé stocker beaucoup de données ici.
* Je ne suis pas entièrement sûr si les utilisateurs peuvent vraiment y accéder, mais la documentation d’Auth0 indique de ne stocker que des préférences dans les métadonnées utilisateur. Voir How can a user access their user_metadata (read/write).
5.6. Comment vérifier si un utilisateur a validé son adresse email ?
Auth0 dispose d’un mécanisme intégré pour voir si les utilisateurs ont confirmé leur adresse email ou non. Cela vous aidera à savoir si les utilisateurs utilisent une adresse email authentique ou une fausse. Par défaut, chaque fois qu’un utilisateur s’inscrit, un email de confirmation est envoyé.
Pour vérifier si un utilisateur spécifique a confirmé son adresse email, allez dans User Management > Users et sélectionnez le profil de l’utilisateur. À côté de l’adresse email, vous verrez si celle-ci a été vérifiée ou non :
Dans l’application Shiny elle-même, vous voudrez certainement différencier ce que l’utilisateur peut voir selon si il a validé son adresse email ou non.
Le problème est que, par défaut, vous n’avez pas accès à cette information depuis l’objet session$userData$auth0_info
(voir 4.2. Accéder aux informations utilisateur après l’authentification pour un rappel).
Vous allez devoir étendre le scope de cette information.
Retournez dans votre fichier de configuration, _auth0.yml
, et ajoutez le champ scope :
name: DataChamp' Article Auth0
remote_url: ""
auth0_config:
api_url: !expr paste0("https://", Sys.getenv("AUTH0_TENANT"), ".", Sys.getenv("AUTH0_REGION"), ".auth0.com")
scope: openid profile email
credentials:
key: !expr Sys.getenv("AUTH0_CLIENT_ID")
secret: !expr Sys.getenv("AUTH0_CLIENT_SECRET")
Par défaut, ce champ ne prend que les valeurs openid
et profile
. En ajoutant email
, vous obtiendrez plus d’informations sur votre objet session$userData$auth0_info
:
Nous avons maintenant deux champs supplémentaires : email et email_verified.
Maintenant, c’est à vous, le développeur Shiny, d’adapter le comportement de l’application en fonction de la valeur de cette variable.
5.7. Mon application plante quand je rafraîchis la page
Vraiment ?
C’est ennuyeux.
Quand vous rafraîchissez la page, en utilisant le bouton “Actualiser” ⟳ de votre navigateur, ou en utilisant F5, ou Ctrl+R, elle plante avec le message d’erreur suivant :
Error in httr::oauth2.0_access_token(api, app(redirect_uri), params$code) :
Forbidden (HTTP 403). Failed to get an access token.
Oui. C’est parce que l’URL de votre application ressemble à ceci :
http://localhost:4050/?code=QGiET0UlOsAMCJddhRhd8voH61iO6sJ4-6yjwXpmPuQrK&state=9Ke1ebSg4K
Vous voyez le code ? C’est un code à usage unique.
Et donc, quand vous rafraîchissez, il essaie d’utiliser le code à nouveau, qui n’est plus valide. Alors vous recevez une erreur Forbidden (HTTP 403).
La solution ?
Supprimer automatiquement le code de l’URL en utilisant ce petit snippet JavaScript :
setTimeout(function(){
var url = new URL(window.location.href);
url.search = '';
history.replaceState(null, '', url.toString());
}, 2000);
Je recommande de l’ajouter à la fin de votre fonction ui
. Dans notre cas, ce serait :
ui <- fluidPage(
titlePanel("Basic App"),
verbatimTextOutput("user_info"),
auth0::logoutButton(),
tags$script(
"setTimeout(function(){
var url = new URL(window.location.href);
url.search = '';
history.replaceState(null, '', url.toString());
}, 2000);"
),
)
auth0::auth0_ui(ui, info = auth0_info)
Je vous explique ce qui se produit :
- La fonction
setTimeout
programme le déclenchement du code après 2000 ms. C’est parce que la partie?code=...
dans l’URL n’apparaît pas immédiatement. Cette valeur est arbitraire, donc n’hésitez pas à l’ajuster. var url = new URL(window.location.href);
définit la variableurl
comme l’URL du navigateur. Ce n’est pas une simple chaîne mais un objetURL
.url.search = '';
définit l’attributsearch
(c’est-à-dire tout ce qui suit le?
dans l’URL) comme chaîne vide.history.replaceState(null, '', url.toString());
remplace l’URL actuelle dans le navigateur par celle que vous venez de modifier.
Voilà.
C’est tout.
Vous savez maintenant tout sur Auth0 !
Qu’attendez-vous ? Commencez à intégrer Auth0 dans votre application Shiny dès aujourd’hui et profitez d’une authentification sécurisée et fluide !
Commentaires