OAuth2 básico en Discourse

:discourse2: Resumen Discourse OAuth2 Basic admite proveedores OAuth2 básicos, asumiendo que disponen de un punto final de API JSON donde se pueden recuperar los detalles del usuario mediante un token.
:open_book: Guía de instalación Este plugin viene incluido en el núcleo de Discourse. No es necesario instalarlo por separado.

Funcionalidades

Este plugin te permite utilizar un proveedor OAuth2 básico como método de autenticación para Discourse. Debería funcionar con muchos proveedores, con la salvedad de que deben proporcionar un punto final JSON para recuperar información sobre el usuario que inicia sesión.

Esto es principalmente útil para personas que utilizan proveedores de inicio de sesión que no son muy populares. Si deseas usar Google, Facebook o Twitter, estos ya vienen incluidos y no necesitas este plugin. También puedes buscar otros proveedores de inicio de sesión en nuestro repositorio de GitHub.

Configuración

Configuración básica

  1. Primero, registra tu aplicación de Discourse con tu proveedor OAuth2. Se requerirá una URI de redirección que será:

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source: Sustituye DISCOURSE_HOST por el valor correspondiente y asegúrate de usar https si está habilitado. El proveedor OAuth2 debe proporcionarte un client ID y un secret, así como varias URLs.

  1. Visita AdministraciónConfiguraciónInicio de sesión OAuth2 y completa la configuración básica para el proveedor OAuth2:
  • oauth2_enabled - marca esta opción para habilitar la función
  • oauth2_client_id - el ID de cliente de tu proveedor
  • oauth2_client_secret - el secreto de cliente de tu proveedor
  • oauth2_authorize_url - la URL de autorización de tu proveedor
  • oauth2_token_url - la URL de token de tu proveedor.

:information_source: Si no logras determinar los valores de la configuración anterior, consulta la documentación para desarrolladores de tu proveedor o contacta con su atención al cliente.

Configuración del punto final JSON del usuario

Discourse ahora puede recibir un token de autorización de tu proveedor OAuth2. Desafortunadamente, Discourse requiere más información para completar la autenticación.

Necesitamos un punto final de API al que se pueda contactar para recuperar información sobre el usuario basándose en el token.

Por ejemplo, el proveedor OAuth2 SoundCloud proporciona una URL así. Si tienes un token OAuth2 para SoundCloud, puedes realizar una solicitud GET a https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN y recibirás un objeto JSON que contiene información sobre el usuario.

Para configurar esto en Discourse, debemos establecer el valor de la configuración oauth2_user_json_url. En este caso, introduciremos el valor:

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

La parte con :token le indica a Discourse que debe reemplazar ese valor con el token de autorización que recibió al completarse la autenticación.

Solo queda un último paso. Debemos decirle a Discourse qué atributos están disponibles en el JSON recibido. Aquí tienes una respuesta de ejemplo 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"
}

Las variables oauth2_json_user_id_path, oauth2_json_username_path, oauth2_json_name_path y oauth2_json_email_path deben configurarse para apuntar a los atributos adecuados en el JSON.

El único atributo obligatorio es id: lo necesitamos para que, cuando el usuario inicie sesión en el futuro, podamos recuperar la cuenta correcta. Los demás son muy útiles si están disponibles, ya que acelerarán el proceso de registro del usuario al prellenarse en el formulario.

Así es como configuré los ajustes de ruta JSON:

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

Usé permalink porque parece más similar a lo que Discourse espera para un nombre de usuario que el campo username en su JSON. Observa que omití la ruta del correo electrónico: SoundCloud no proporciona un correo electrónico, por lo que el usuario deberá proporcionarlo y verificarlo la primera vez que se registre en Discourse.

Si las propiedades que deseas de tu objeto JSON están anidadas, puedes usar puntos. Por ejemplo, si la API devolviera una estructura diferente como esta:

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

Podrías usar user.id para oauth2_json_user_id_path y user.email.address para oauth2_json_email_path.

Si la clave en sí incluye puntos, deberás poner comillas dobles alrededor de ella o escapar los puntos con una barra invertida. Por ejemplo, dado este JSON:

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

Especificarías la ruta como example\.com/uid o "example.com/uid".

Sincronización de grupos y campos de usuario

  • oauth2_json_groups_path: Ruta JSON que contiene los grupos del usuario como un array de cadenas. Después de que el primer miembro haya iniciado sesión, estos grupos estarán disponibles para selección en la sección «Grupos asociados» de la configuración de grupos de Discourse. Déjalo en blanco para desactivar la sincronización de grupos.

  • oauth2_user_field_mappings: Mapeos de rutas JSON que se almacenarán en los campos de usuario de Discourse. Los campos de usuario se identifican por su ID numérico, que puede encontrarse en la URL al editarlos desde el panel de administración.

:warning: Si configuras oauth2_json_email_path, el proveedor OAuth2 debe confirmar que el usuario es propietario de esa dirección de correo electrónico. ¡No hacerlo puede resultar en la toma de control de cuentas en Discourse!

:discourse2: ¿Alojado por nosotros? Este plugin está disponible en nuestros planes Business y Enterprise. OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

:spiral_notepad: ¿Necesitas automatizar los registros de usuarios? Consulta Auto-provisioning user accounts when SSO is enabled

28 Me gusta
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
Auto-provisioning user accounts when SSO is enabled
Configure sign up and log in with Auth0 using the OAuth2 Basic Plugin
SSO with TownNews CMS
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)
Error during SSO integration - Wholistic Minds
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 and Auth0
Migrate a Jive Clearspace forum to Discourse

Hola,
Estamos intentando integrar Discourse con nuestra aplicación usando OAuth2 Basic pero estamos recibiendo el siguiente error en los registros:
Nota: Estamos usando NGROK ya que estamos depurando la conexión.

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}

Dejamos los parámetros “oauth2 callback user id path” y “oauth2 callback user info paths” vacíos.

Cualquier idea es apreciada.

¿Puedo usar esto para autenticarme con el servicio XBL de Microsoft?

Supongo que la lógica sería similar a esta?

Hola a todos. Intento configurar este plugin con nuestro servidor Oauth2 interno con el flujo de código de autorización.

Cuando un usuario hace clic en “Conectar con Oauth”, el endpoint /authorize funciona y se devuelve un código al callback. Pero luego Discourse muestra un error genérico 500 “Oops. El software que impulsa este foro de discusión encontró un problema inesperado” y el endpoint /token no se accede.

El registro de errores dice esto:
OAuth2::ConnectionError (FinalDestination: todas las IPs resueltas fueron desautorizadas) 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

Según entiendo, ¿hay un problema con alguna dirección IP? Actualmente el servidor Oauth2 está alojado en mi entorno de desarrollo (localhost) y los endpoints de autorización y token están configurados en consecuencia. ¿Es un problema?

Encontré el problema:

  1. Por alguna razón, el endpoint /token nunca se llamó. Después de configurar el máximo de opciones en los parámetros de administrador relacionados con oauth, el endpoint se llamó sin respuesta.
  2. Olvidé que era el servidor Discourse el que llamaría al endpoint /token y no el webclient. Por lo tanto, el servidor no pudo alcanzar mi servidor Oauth2 localhost. Poner nuestro servidor Oauth2 detrás de un dominio resolvió el problema.

Ahora, puedo conectar usuarios existentes pero no entiendo cómo iniciar sesión con nuevos usuarios a través de este plugin.
Si el usuario inicia sesión con oauth, recibe un error que dice que no tiene una cuenta activa en el servidor Discourse. Lo cual es normal ya que es un nuevo usuario.

¿Hay un callback dedicado para iniciar sesión en lugar de iniciar sesión? ¿O un parámetro específico para configurar para permitir la creación de cuentas?

Mi servidor oauth de la empresa generaba una respuesta JSON de /profile con un pequeño error tipográfico en un campo. Todo estuvo bien después de corregir el error tipográfico.
¡Pero tengo que decir que los registros de Discourse pueden ser muy engañosos! No había nada malo con la devolución de llamada.

Hola equipo:

Tengo un problema al extraer el ID que necesito para mi solicitud JSON de usuario de la respuesta de autorización. Al leer la documentación, parece que el ID de cuenta se envía en una matriz anidada:

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"]
      }
   ]
}

He intentado establecer la ruta del ID de usuario de la devolución de llamada oauth2 en permissions[0].accountId, pero el valor de mi uid siempre está en blanco. Desafortunadamente, las llamadas para extraer el JSON de usuario requieren este accountId en la URL JSON.

Pude hacer que esto funcionara pasando permissions.first.accountId. Descubrí que cuando pasé permissions a una propiedad de prueba, la matriz ya se analizó como una matriz de Ruby. Desafortunadamente, los campos parecen rechazar la sintaxis de Ruby para llamar a elementos de matriz y cualquier intento de usar la sintaxis de Javascript resultaría en un TypeError String a Integer. Afortunadamente, Ruby tenía la sintaxis anterior, ¿es este el método previsto?

Acabo de hacer que esto funcione con Authentik OAuth2, sin embargo, hubo algunos problemas con la configuración de oauth2 user json url. Usé el endpoint user_info de Authentik para eso (/application/o/userinfo/), sin embargo, no sabía cómo mapear los campos. Para cualquiera que busque cómo configurar Discourse con OAuth2 de Authentik, aquí está el resumen:

  • Ruta del ID de usuario: preferred_username
  • Ruta del nombre de usuario: preferred_username
  • Ruta del nombre: name
  • Ruta del correo electrónico: email
  • Ruta de verificación del correo electrónico: email_verified
  • Avatar: vacío.

Tuve los siguientes problemas:

  1. Al principio, olvidé la barra diagonal al final en la URL JSON https://DOMAIN/application/o/userinfo/. Esto llevó a que la solicitud de información del usuario (enlace permanente a la fuente) devolviera un código HTTP 301, lo que provocó que el inicio de sesión fallara. No sé si la barra diagonal al final debería estar allí por especificación, pero quizás sería bueno manejar correctamente los 301.
  2. Depurar esto resultó complicado. La configuración oauth2 debug auth fue un salvavidas, pero… Logster trunca el registro de depuración antes de volcar realmente los datos de respuesta significativos. Tuve que modificar manualmente en el contenedor la línea de registro a
    log("user_json_response: #{user_json_response.status} #{user_json_response.headers} #{user_json_response.body}")
    
    ¿Quizás esa línea de registro podría actualizarse? Supongo que podría ayudar a otras personas a descubrir la ruta de los atributos JSON.
4 Me gusta

Acabo de configurar Auth0 con el plugin y he descubierto que los avatares no se obtienen.

Estas son las configuraciones relevantes:

  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

En el registro de depuración, puedo ver que el elemento picture está configurado en la respuesta JSON, pero el avatar del usuario no cambia, ni para usuarios nuevos ni para los existentes.

¿Qué me he perdido?

¿Cuál es la mejor manera de reemplazar el icono en el botón de inicio de sesión con otro icono o una imagen?

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

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

parece suficiente pero un poco improvisado.

2 Me gusta

Parece que el plugin solo actualiza el avatar/nombre de usuario al crear el usuario inicialmente, no cada vez que inicia sesión.

¿Hay alguna forma de solucionar esto y hacer que el plugin también actualice el avatar al iniciar sesión/reconectar?

Puedes usar la configuración auth overrides email, auth overrides username y auth overrides name para que esas cosas se apliquen en futuros inicios de sesión. Me temo que actualmente no tenemos una configuración similar para avatares, pero sería pr-welcome

2 Me gusta

¡Gracias! De hecho, los encontré más tarde. Hice un fork del repositorio y agregué mis propias versiones para que esto funcionara con Roblox, lo que incluyó la anulación para los avatares. Que creo que simplemente usa la anulación de avatar de DiscourseConnect para que la gente no pueda cambiarla.

Sin embargo, desearía que Roblox no proporcionara un correo electrónico en OAuth, así que lamentablemente necesito que se registren con un correo electrónico. Pero eso no es un problema para ustedes, jaja.

Se dividió una publicación a un nuevo tema: El inicio de sesión de Twitter no funciona en meta

¿Alguien sabe si esto todavía funciona?

Sí. Estoy seguro de que este plugin funciona. :+1:

1 me gusta

Hola, pude integrar este plugin en mi discourse discuss.frontendlead.com, estoy usando teachable oauth https://docs.teachable.com/docs/oauth-quickstart-guide

Sin embargo, solo quiero permitir que las personas se registren exitosamente si y solo si tienen una cuenta de pago activa en teachable. Me imagino que necesito agregar funcionalidad personalizada en el plugin para manejar esto. Me pregunto si ustedes o incluso yo podemos introducir otro campo en la configuración llamado código personalizado después de oauth, que permita a los desarrolladores realizar acciones específicas después del registro. O si hay mejores sugerencias, por favor házmelo saber.

Editar: Hice un fork del repositorio y lo hice funcionar aquí:

Si alguien más que usa teachable está intentando hacer lo mismo, mi repositorio funcionará de inmediato, lo único es que si no compraste un curso, dirá que necesitas ir a mi dominio para comprarlo. Es posible que desees actualizar eso para tu propio caso de uso.

2 Me gusta

¡Eso es genial!

Existe una situación similar con el registro OAuth2 con el plugin Discourse Patreon. Cuando se habilita “Iniciar sesión con Patreon”, permite que cualquier persona con una cuenta de Patreon se registre en el sitio de Discourse. Lo que los propietarios del sitio generalmente quieren es permitir que solo sus patrocinadores puedan registrarse en cuentas de Discourse. Me pregunto si Patreon devuelve detalles que permitirían agregar una lógica similar a la autenticación de Patreon.

1 me gusta

Tengo el mismo error que @qlands arriba.

Mi plan inicial era enviar la información del perfil en el token. Al ver que no funcionó, lo simplifiqué para intentar el enfoque JSON. Pero ni siquiera llega al punto de llamar al archivo JSON.

El mensaje de error es:

(oauth2_basic) Fallo de autenticación! invalid_credentials: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
}

¿Ves algo malo en la respuesta anterior?
¿Por qué el plugin generaría un error invalid_credentials mientras que el servidor OAuth2 respondió con un 200 y un token?