OAuth2 de base pour Discourse

:discourse2: Résumé Discourse OAuth2 Basic prend en charge les fournisseurs OAuth2 de base, en supposant qu’ils disposent d’un point de terminaison API JSON permettant de récupérer les détails de l’utilisateur via un jeton.
:open_book: Guide d’installation Ce plugin est intégré au cœur de Discourse. Aucune installation séparée du plugin n’est nécessaire.

Fonctionnalités

Ce plugin vous permet d’utiliser un fournisseur OAuth2 de base comme méthode d’authentification pour Discourse. Il devrait fonctionner avec de nombreux fournisseurs, à condition qu’ils fournissent un point de terminaison JSON pour récupérer les informations sur l’utilisateur qui se connecte.

Cela est principalement utile pour les personnes utilisant des fournisseurs de connexion peu populaires. Si vous souhaitez utiliser Google, Facebook ou Twitter, ceux-ci sont inclus par défaut et vous n’avez pas besoin de ce plugin. Vous pouvez également consulter d’autres fournisseurs de connexion dans notre dépôt Github.

Configuration

Configuration de base

  1. Tout d’abord, enregistrez votre application Discourse auprès de votre fournisseur OAuth2. Il vous sera demandé une URI de redirection qui sera :

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source: Remplacez DISCOURSE_HOST par la valeur appropriée et assurez-vous d’utiliser https si activé. Le fournisseur OAuth2 devrait vous fournir un client ID et un secret, ainsi que plusieurs URL.

  1. Accédez à AdminParamètresConnexion OAuth2 et remplissez la configuration de base pour le fournisseur OAuth2 :
  • oauth2_enabled - cochez cette case pour activer la fonctionnalité
  • oauth2_client_id - l’ID client fourni par votre fournisseur
  • oauth2_client_secret - le secret client fourni par votre fournisseur
  • oauth2_authorize_url - l’URL d’autorisation de votre fournisseur
  • oauth2_token_url - l’URL de jeton de votre fournisseur.

:information_source: Si vous ne parvenez pas à déterminer les valeurs des paramètres ci-dessus, consultez la documentation pour les développeurs de votre fournisseur ou contactez son support client.

Configuration du point de terminaison JSON de l’utilisateur

Discourse peut désormais recevoir un jeton d’autorisation de votre fournisseur OAuth2. Malheureusement, Discourse nécessite plus d’informations pour pouvoir finaliser l’authentification.

Nous avons besoin d’un point de terminaison API auquel il est possible de se connecter pour récupérer des informations sur l’utilisateur à partir du jeton.

Par exemple, le fournisseur OAuth2 SoundCloud fournit une telle URL. Si vous disposez d’un jeton OAuth2 pour SoundCloud, vous pouvez effectuer une requête GET vers https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN et recevrez un objet JSON contenant des informations sur l’utilisateur.

Pour configurer cela dans Discourse, nous devons définir la valeur du paramètre oauth2_user_json_url. Dans ce cas, nous entrerons la valeur suivante :

https://api.soundcloud.com/me?oauth_token=:token

La partie contenant :token indique à Discourse qu’il doit remplacer cette valeur par le jeton d’autorisation reçu lors de la fin de l’authentification.

Il reste une dernière étape à effectuer. Nous devons indiquer à Discourse quels attributs sont disponibles dans le JSON reçu. Voici un exemple de réponse de SoundCloud :

{
  "id": 3207,
  "permalink": "jwagener",
  "username": "Johannes Wagener",
  "uri": "https://api.soundcloud.com/users/3207",
  "permalink_url": "http://soundcloud.com/jwagener",
  "avatar_url": "http://i1.sndcdn.com/avatars-000001552142-pbw8yd-large.jpg?142a848",
  "country": "Germany",
  "full_name": "Johannes Wagener",
  "city": "Berlin"
}

Les variables oauth2_json_user_id_path, oauth2_json_username_path, oauth2_json_name_path et oauth2_json_email_path doivent être configurées pour pointer vers les attributs appropriés dans le JSON.

Le seul attribut obligatoire est id - nous en avons besoin afin de pouvoir récupérer le bon compte lorsque l’utilisateur se connecte à l’avenir. Les autres sont excellents s’ils sont disponibles : ils rendront le processus d’inscription plus rapide pour l’utilisateur car ils seront préremplis dans le formulaire.

Voici comment j’ai configuré les paramètres de chemin JSON :

  oauth2_json_user_id_path: 'id'
  oauth2_json_username_path: 'permalink'
  oauth2_json_name_path: 'full_name'

J’ai utilisé permalink car il semble plus similaire à ce que Discourse attend pour un nom d’utilisateur que le nom d’utilisateur dans leur JSON. Notez que j’ai omis le chemin de l’e-mail : SoundCloud ne fournit pas d’e-mail, l’utilisateur devra donc le fournir et le vérifier lors de sa première inscription sur Discourse.

Si les propriétés que vous souhaitez de votre objet JSON sont imbriquées, vous pouvez utiliser des points. Par exemple, si l’API renvoyait une structure différente comme celle-ci :

{
  "user": {
    "id": 1234,
    "email": {
      "address": "test@example.com"
    }
  }
}

Vous pourriez utiliser user.id pour oauth2_json_user_id_path et user.email.address pour oauth2_json_email_path.

Si la clé elle-même contient des points, vous devrez mettre des guillemets doubles autour d’elle ou échapper les points avec une barre oblique inverse. Par exemple, étant donné ce JSON :

{
  "example.com/uid": "myuid"
}

Vous spécifieriez le chemin sous la forme example\.com/uid ou "example.com/uid"

:warning: Si vous définissez oauth2_json_email_path, le fournisseur OAuth2 doit confirmer que l’utilisateur possède bien cette adresse e-mail. Le non-respect de cette règle peut entraîner une prise de contrôle de compte dans Discourse !

:discourse2: Hébergé par nous ? Ce plugin est disponible dans nos offres Business et Entreprise. OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

:spiral_notepad: Besoin d’automatiser les inscriptions d’utilisateurs ? Consultez Auto-provisioning user accounts when SSO is enabled

28 « J'aime »
Keycloak with Discourse
Discourse SSO with OAuth2
Login from another user database
Shopify Integration
How can we enable Auth0 SSO in Discourse
OAuth2 integration with Drupal
OAuth connection of discourse
Login flow (Flask -> Discourse -> Flask) with OAuth
How to use Oauth2 service provided by discourse?
How to login to discourse from external website
Is "partial" SSO possible?
Set up Salesforce auth using OAuth2 basic support plugin
How to force users link phone number when they using Discourse?
OAuth2 Custom Redirects Plugin
Custom Login / Registration from another API
Login on discourse using mastodon credentials
Open source will support customized provider SSO
Oauth2 with fusionauth cert issues
Migrate a Jive Clearspace forum to Discourse
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
Error during SSO integration - Wholistic Minds
What is supposed to go in “DISCOURSE_HOST”?
Custom Provider log-in with OAuth only sign-up/log-in
Discord, Google and Microsoft login, is oAuth2 enough?
Populating email field on login page
CodeBerg support
Gate our community to just members of our Shopify site?
Intergrate Discourse with keycloak
Integration into custom auth system where emails are not unique?
Twitter login doesn't work on meta
Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso)
Question about Docker Manager?
Discourse OpenID Connect (OIDC)
🧩 How to Build an Android App User Community with Discourse? [HeyApks Project]
Bundling more popular plugins with Discourse core
Drupal 8 and Discourse shared SSO
Discourse for self hosting
Discourse + Intercom (Current User Id)
Auto-provisioning user accounts when SSO is enabled
ADFS Authentication
Pulling user auth0 sub from OAuth2.0 plugin
Suggestion for improving Integrated Authentication development
Github and Twitter Login/Sign-Up Functionality?
Automatically creating a user when logging in with Webflow/Memberspace
Switching out authentication for a passwordless alternative
Removing Yahoo login from Core, and deprecating OpenID 2.0
Shopify Integration
SSO with TownNews CMS
SSO and Auth0

Bonjour,
Nous essayons d’intégrer Discourse à notre application en utilisant OAuth2 Basic mais nous rencontrons l’erreur suivante dans les logs :
Note : Nous utilisons NGROK pour déboguer la connexion.

OAuth2 Debugging: request POST https://formshare.ngrok.io/oauth2/token

Headers: {"User-Agent"=>"Faraday v1.9.3", "Content-Type"=>"application/x-www-form-urlencoded", "Authorization"=>"Basic S2k2SFZtTVpuSTFHUExiRXVlWVJDN4CbOkNvb1k0anlQemt3dWNRV21Sa2FWOVNnbHZLbjJFT3cxc3BIMmtMck9yY21vNDM4Tg=="}

Body: {"client_id"=>"Ki6HVmMZnI1GPLbEueYRC4Cb", "client_secret"=>"...some_secret_...", "grant_type"=>"authorization_code", "code"=>"5pPCrsp0pZ84373MNaHh2cuskfc8AlbfmdwMBFIVW4n4z9aX", :redirect_uri=>"https://community.formshare.org/auth/oauth2_basic/callback"}

------------------

OAuth2 Debugging: response status 200

From POST https://formshare.ngrok.io/oauth2/token

Headers: {"content-length"=>"108", "content-type"=>"text/html; charset=UTF-8", "date"=>"Thu, 01 Sep 2022 21:42:08 GMT", "ngrok-trace-id"=>"79cdc3f1c3eae5e37a30796aebbf9bd6", "server"=>"gunicorn"}

Body: {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

-----------------------------------

(oauth2_basic) Authentication failure! invalid_credentials: OAuth2::Error, {"token_type": "Bearer", "access_token": "p0FVuwjSXL1ZINEklMAVqUlpZxSll1SgnbpE8YWP4C", "expires_in": 864000}

Nous avons laissé les paramètres “oauth2 callback user id path” et “oauth2 callback user info paths” vides.

Toute idée est appréciée.

Puis-je l’utiliser pour m’authentifier auprès du service XBL de Microsoft ?

Je suppose que la logique serait similaire à ceci ?

Bonjour à tous. J’essaie de configurer ce plugin avec notre serveur Oauth2 interne avec le flux d’autorisation par code.

Lorsqu’un utilisateur clique sur « Se connecter avec Oauth », le point de terminaison /authorize fonctionne et un code est renvoyé au callback. Mais ensuite, Discourse affiche une erreur générique 500 « Oops. Le logiciel qui alimente ce forum de discussion a rencontré un problème inattendu » et le point de terminaison /token n’est pas accédé.

Le journal d’erreurs dit ceci :
OAuth2::ConnectionError (FinalDestination: all resolved IPs were disallowed) lib/final_destination/ssrf_detector.rb:74:in lookup_and_filter_ips' lib/final_destination/http.rb:13:in connect’ lib/midd

hostname discourse-app
process_id 653
application_version 702f27e6ee10ac257f5fee3f331d05f5fa5d7a45
HTTP_HOST *****
REQUEST_METHOD GET
HTTP_USER_AGENT Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
HTTP_REFERER *****
HTTP_X_FORWARDED_FOR *****
HTTP_X_REAL_IP *****
time 10:25 pm
params
code def50200babf84f7376f99fefa34369d876566b6bc0a341d8fba431999a72549ac06f6aad01df6fa43061707c525ba5d725ad
state 20139e0a134a5972566d4ddb6f7f9092a2cddb9e5216973a

D’après ce que je comprends, il y a un problème avec une adresse IP ? Actuellement, le serveur Oauth2 est hébergé dans mon environnement de développement (localhost) et les points de terminaison d’autorisation et de jeton sont configurés en conséquence. Est-ce un problème ?

Problème trouvé :

  1. Pour une raison quelconque, le point de terminaison /token n’a jamais été appelé. Après avoir rempli un maximum d’options dans les paramètres d’administration liés à l’oauth, le point de terminaison a été appelé sans réponse.
  2. J’ai oublié que c’était le serveur Discourse qui appellerait le point de terminaison /token et non le webclient. Par conséquent, le serveur ne pouvait pas atteindre mon serveur Oauth2 localhost. Placer notre serveur Oauth2 derrière un domaine a résolu le problème.

Maintenant, je peux connecter les utilisateurs existants mais je ne comprends pas comment connecter de nouveaux utilisateurs via ce plugin.
Si l’utilisateur se connecte avec oauth, il reçoit une erreur indiquant qu’il n’a pas de compte actif sur le serveur Discourse. Ce qui est normal puisqu’il s’agit d’un nouvel utilisateur.

Existe-t-il un rappel dédié pour connecter l’utilisateur au lieu de le faire entrer ? Ou un paramètre spécifique à définir pour autoriser la création de compte ?

Mon serveur oauth d’entreprise générait une réponse JSON /profile avec une petite faute de frappe dans un champ. Tout s’est bien passé après avoir corrigé la faute de frappe.
Mais je dois dire que les logs de Discourse peuvent être très trompeurs ! Rien n’allait mal avec le rappel.

Salut l’équipe,

J’ai un problème pour extraire l’ID dont j’ai besoin pour ma requête JSON utilisateur de la réponse d’autorisation. En lisant la documentation, il semble que l’ID de compte soit envoyé dans un tableau imbriqué :

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"Bearer",
   "expires_in":1800,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "permissions":[
      {
        "accountId":123,
        "availableScopes":["contacts_view", "contacts_me", 
"contacts_edit", "finances_view", "events_view"]
      }
   ]
}

J’ai essayé de définir le chemin de l’ID utilisateur du callback oauth2 sur permissions[0].accountId, mais la valeur de mon uid est toujours vide. Malheureusement, les appels pour extraire le JSON utilisateur nécessitent cet accountId dans l’URL JSON.

J’ai réussi à faire fonctionner cela en passant permissions.first.accountId. J’ai constaté qu’en passant les permissions dans une propriété de test, le tableau était déjà analysé comme un tableau Ruby. Malheureusement, les champs semblent rejeter la syntaxe Ruby pour appeler des éléments de tableau et toute tentative d’utilisation de la syntaxe Javascript entraînerait une TypeError String to Integer. Heureusement, Ruby avait la syntaxe ci-dessus, est-ce la méthode prévue ?

J’ai réussi à faire fonctionner cela avec Authentik OAuth2, mais il y a eu quelques problèmes avec le paramètre oauth2 user json url. J’ai utilisé le point de terminaison user_info d’Authentik pour cela (/application/o/userinfo/), mais je ne savais pas comment mapper les champs. Pour ceux qui cherchent comment configurer Discourse avec l’OAuth2 d’Authentik, voici le résumé :

  • Chemin de l’ID utilisateur : preferred_username
  • Chemin du nom d’utilisateur : preferred_username
  • Chemin du nom : name
  • Chemin de l’e-mail : email
  • Chemin de l’e-mail vérifié : email_verified
  • Avatar : vide.

J’ai eu les problèmes suivants :

  1. Au début, j’ai oublié la barre oblique finale dans l’URL JSON https://DOMAIN/application/o/userinfo/. Cela a conduit la requête d’informations utilisateur (lien permanent vers la source) à retourner un code HTTP 301, ce qui a fait échouer la connexion. Je ne sais pas si la barre oblique finale devrait être là selon la spécification, mais il serait peut-être bon de gérer correctement les 301.
  2. Le débogage s’est avéré délicat. Le paramètre oauth2 debug auth a été d’une grande aide, mais… Logster tronque le journal de débogage avant de réellement afficher les données de réponse significatives. J’ai dû modifier manuellement dans le conteneur la ligne de journalisation pour
    log("user_json_response: #{user_json_response.status} #{user_json_response.headers} #{user_json_response.body}")
    
    Peut-être que cette ligne de journalisation pourrait être mise à jour ? Je suppose que cela pourrait aider d’autres personnes à trouver le chemin des attributs JSON.
4 « J'aime »

Je viens de configurer Auth0 avec le plugin et j’ai constaté que les avatars ne sont pas récupérés.

Voici les paramètres pertinents :

  DISCOURSE_OAUTH2_ENABLED: true
  DISCOURSE_OAUTH2_CLIENT_ID: '${DISCOURSE_OAUTH2_CLIENT_ID}'
  DISCOURSE_OAUTH2_CLIENT_SECRET: '${DISCOURSE_OAUTH2_CLIENT_SECRET}'
  DISCOURSE_OAUTH2_AUTHORIZE_URL: '${DISCOURSE_OAUTH2_ISSUER}/authorize?connection=xxx&login_options=yyy'
  DISCOURSE_OAUTH2_TOKEN_URL: '${DISCOURSE_OAUTH2_ISSUER}/oauth/token'
  DISCOURSE_OAUTH2_USER_JSON_URL: '${DISCOURSE_OAUTH2_ISSUER}/userinfo'
  DISCOURSE_OAUTH2_SCOPE: 'email openid profile'
  DISCOURSE_OAUTH2_JSON_USER_ID_PATH: 'sub'
  DISCOURSE_OAUTH2_JSON_USERNAME_PATH: 'nickname'
  DISCOURSE_OAUTH2_JSON_NAME_PATH: 'name'
  DISCOURSE_OAUTH2_JSON_EMAIL_PATH: 'email'
  DISCOURSE_OAUTH2_JSON_EMAIL_VERIFIED_PATH: 'email_verified'
  DISCOURSE_OAUTH2_JSON_AVATAR_PATH: 'picture'
  DISCOURSE_OAUTH2_EMAIL_VERIFIED: true
  DISCOURSE_OAUTH2_OVERRIDES_EMAIL: true
  DISCOURSE_OAUTH2_ALLOW_ASSOCIATION_CHANGE: false

Dans le journal de débogage, je peux voir que l’élément picture est défini dans la réponse JSON, mais l’avatar de l’utilisateur ne change pas, ni pour les nouveaux utilisateurs ni pour les utilisateurs existants.

Qu’ai-je manqué ?

Quelle est la meilleure façon de remplacer l’icône du bouton de connexion par une autre icône ou une image ?

.btn-social.oauth2_basic:before {
    content: url('https://www.contoso.com/path/to/image');
}

.btn-social.oauth2_basic > svg {
    display: none;
}

semble suffisant mais un peu artisanal.

2 « J'aime »

Il semble que le plugin ne mette à jour l’avatar/nom d’utilisateur que lors de la création initiale de l’utilisateur, et non à chaque connexion.

Y a-t-il un moyen de corriger cela et de faire en sorte que le plugin mette également à jour l’avatar lors de la connexion/reconnexion ?

Vous pouvez utiliser les paramètres auth overrides email, auth overrides username et auth overrides name pour que ces éléments s’appliquent lors des futures connexions. Je crains que nous n’ayons pas actuellement de paramètre similaire pour les avatars, mais ce serait pr-welcome

2 « J'aime »

Merci ! Je les ai en fait trouvés plus tard. J’ai forké le dépôt et ajouté mes propres versions pour que cela fonctionne avec Roblox, ce qui incluait la surcharge pour les avatars. Ce qui, je crois, utilise simplement la surcharge d’avatar DiscourseConnect pour que les gens ne puissent pas la changer.

Une chose que je regrette cependant, c’est que Roblox ne fournisse pas d’e-mail sur OAuth, j’ai donc malheureusement besoin qu’ils s’inscrivent avec un e-mail. mais ce n’est pas un problème pour vous haha.

Un message a été divisé en un nouveau sujet : La connexion Twitter ne fonctionne pas sur meta

Quelqu’un sait si cela fonctionne toujours ?

Oui. Je suis convaincu que ce plugin fonctionne. :+1:

1 « J'aime »

Salut, j’ai réussi à intégrer ce plugin dans mon discourse discuss.frontendlead.com, j’utilise teachable oauth https://docs.teachable.com/docs/oauth-quickstart-guide

Cependant, je veux seulement permettre aux gens de s’inscrire avec succès si et seulement s’ils ont un compte payant actuel sur Teachable. J’imagine que je dois ajouter une fonctionnalité personnalisée dans le plugin pour gérer cela ? Je me demande, est-ce que vous ou moi pouvons introduire un autre champ dans les paramètres appelé code personnalisé après oauth, qui permet aux développeurs d’effectuer des actions spécifiques après l’inscription ? Ou s’il y a de meilleures suggestions, faites-le moi savoir.

Edit : J’ai forké le dépôt et j’ai réussi à le faire fonctionner ici :

Si quelqu’un d’autre utilisant Teachable essaie de faire la même chose, mon dépôt fonctionnera directement, la seule chose est que si vous n’avez pas acheté de cours, il sera dit que vous devez aller sur mon domaine pour l’acheter. vous voudrez peut-être mettre à jour cela pour votre propre cas d’utilisation.

2 « J'aime »

C’est super !

Il y a une situation similaire avec l’enregistrement OAuth2 avec le plugin Discourse Patreon. Lorsque “Se connecter avec Patreon” est activé, il permet à toute personne ayant un compte Patreon de s’inscrire sur le site Discourse. Ce que les propriétaires de sites veulent généralement, c’est de permettre uniquement à leurs supporters de pouvoir s’inscrire sur Discourse. Je me demande si des détails sont renvoyés par Patreon qui permettraient d’ajouter une logique similaire à l’authentification Patreon ?

1 « J'aime »

J’ai exactement la même erreur que @qlands ci-dessus.

Mon plan initial était d’envoyer les informations de profil dans le token. Voyant que cela ne fonctionnait pas, j’ai réduit le code pour essayer l’approche JSON. Mais il n’arrive même pas au point d’appeler le fichier JSON.

Le message d’erreur est :

(oauth2_basic) Échec de l'authentification ! invalid_credentials: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
}

Voyez-vous quelque chose qui ne va pas dans la réponse ci-dessus ?
Pourquoi le plugin générerait-il une erreur invalid_credentials alors que le serveur OAuth2 a répondu avec un 200 et un token ?