OAuth2 Básico no Discourse

:discourse2: Resumo Discourse OAuth2 Basic suporta provedores OAuth2 básicos, assumindo que eles tenham um endpoint de API JSON onde os detalhes do usuário podem ser recuperados por token.
:open_book: Guia de Instalação Este plugin está incluído no núcleo do Discourse. Não há necessidade de instalá-lo separadamente.

Recursos

Este plugin permite que você use um provedor OAuth2 básico como autenticação para o Discourse. Deve funcionar com muitos provedores, com a ressalva de que eles devem fornecer um endpoint JSON para recuperar informações sobre o usuário que está fazendo login.

Isso é principalmente útil para pessoas que estão usando provedores de login que não são muito populares. Se você quiser usar Google, Facebook ou Twitter, eles já estão incluídos e você não precisa deste plugin. Você também pode procurar outros provedores de login em nosso Repositório no Github.

Configuração

Configuração Básica

  1. Primeiro, registre sua aplicação Discourse com seu provedor OAuth2. Será necessário um URI de Redirecionamento que será:

    http://DISCOURSE_HOST/auth/oauth2_basic/callback

:information_source: Substitua DISCOURSE_HOST pelo valor apropriado e certifique-se de estar usando https se estiver habilitado. O provedor OAuth2 deve fornecer um client ID e secret, bem como alguns URLs.

  1. Acesse AdminConfiguraçõesLogin OAuth2 e preencha a configuração básica para o provedor OAuth2:
  • oauth2_enabled - marque esta opção para habilitar o recurso
  • oauth2_client_id - o client ID do seu provedor
  • oauth2_client_secret - o client secret do seu provedor
  • oauth2_authorize_url - URL de autorização do seu provedor
  • oauth2_token_url - URL de token do seu provedor.

:information_source: Se você não conseguir descobrir os valores das configurações acima, consulte a documentação de desenvolvedor do seu provedor ou entre em contato com o suporte ao cliente deles.

Configurando o Endpoint de Usuário JSON

O Discourse agora é capaz de receber um token de autorização do seu provedor OAuth2. Infelizmente, o Discourse precisa de mais informações para completar a autenticação.

Precisamos de um endpoint de API que possa ser acessado para recuperar informações sobre o usuário com base no token.

Por exemplo, o provedor OAuth2 SoundCloud fornece tal URL. Se você tiver um token OAuth2 para o SoundCloud, pode fazer uma solicitação GET para https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN e receberá um objeto JSON contendo informações sobre o usuário.

Para configurar isso no Discourse, precisamos definir o valor da configuração oauth2_user_json_url. Neste caso, inseriremos o valor:

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

A parte com :token informa ao Discourse que ele precisa substituir esse valor pelo token de autorização recebido quando a autenticação foi concluída.

Há um último passo para completar. Precisamos informar ao Discourse quais atributos estão disponíveis no JSON recebido. Aqui está uma resposta de exemplo do 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": "Alemanha",
  "full_name": "Johannes Wagener",
  "city": "Berlim"
}

As variáveis oauth2_json_user_id_path, oauth2_json_username_path, oauth2_json_name_path e oauth2_json_email_path devem ser configuradas para apontar para os atributos apropriados no JSON.

O único atributo obrigatório é id - precisamos dele para que, quando o usuário fizer login no futuro, possamos recuperar a conta correta. Os outros são ótimos se disponíveis — eles tornarão o processo de cadastro mais rápido para o usuário, pois serão pré-preenchidos no formulário.

Veja como configurei as configurações de caminho JSON:

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

Usei permalink porque parece mais semelhante ao que o Discourse espera para um nome de usuário do que o username em seu JSON. Note que omiti o caminho do e-mail: o SoundCloud não fornece um e-mail, então o usuário terá que fornecer e verificar isso quando se cadastrar pela primeira vez no Discourse.

Se as propriedades que você deseja do seu objeto JSON estiverem aninhadas, você pode usar pontos. Por exemplo, se a API retornasse uma estrutura diferente como esta:

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

Você poderia usar user.id para o oauth2_json_user_id_path e user.email.address para oauth2_json_email_path.

Se a própria chave incluir pontos, você precisará colocá-la entre aspas duplas ou escapar os pontos com uma barra invertida. Por exemplo, dado este JSON:

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

Você especificaria o caminho como example\.com/uid ou "example.com/uid".

:warning: Se você definir oauth2_json_email_path, o provedor OAuth2 deve confirmar que o usuário é o dono desse endereço de e-mail. Não fazer isso pode resultar em tomada de conta no Discourse!

:discourse2: Hospedado por nós? Este plugin está disponível em nossos planos Business e Enterprise. OAuth 2.0 & OpenID Connect Support | Discourse - Civilized Discussion

:spiral_notepad: Precisa automatizar cadastros de usuários? Veja Auto-provisioning user accounts when SSO is enabled

28 curtidas
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

Olá,
Estamos tentando integrar o Discourse com nosso aplicativo usando OAuth2 Basic, mas estamos recebendo o seguinte erro nos logs:
Nota: Estamos usando NGROK para depurar a conexão.

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}

Deixamos os parâmetros “oauth2 callback user id path” e “oauth2 callback user info paths” vazios.

Qualquer ideia é bem-vinda.

Posso usar isto para autenticar com o serviço XBL da Microsoft?

Presumo que a lógica seria semelhante a esta?

Olá a todos. Estou tentando configurar este plugin com nosso servidor Oauth2 interno com fluxo de código de autorização.

Quando um usuário clica em “Conectar com Oauth”, o endpoint /authorize funciona e um código é retornado para o callback. Mas então o Discourse mostra um erro genérico 500 “Oops. O software que alimenta este fórum de discussão encontrou um problema inesperado” e o endpoint /token não é acessado.

O log de erros diz o seguinte:
OAuth2::ConnectionError (FinalDestination: todos os IPs resolvidos foram desautorizados) 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 20139e0a134a5972566d4ddb9e5216973a

Pelo que entendi, há um problema com algum endereço IP? Atualmente, o servidor Oauth2 está hospedado em meu ambiente de desenvolvimento (localhost) e os endpoints de autorização e token estão configurados de acordo. Isso é um problema?

Encontrei o problema:

  1. Por algum motivo, o endpoint /token nunca foi chamado. Após preencher o máximo de opções nos parâmetros de administrador relacionados ao OAuth, o endpoint foi chamado sem resposta.
  2. Esqueci que era o servidor Discourse que chamaria o endpoint /token e não o webclient. Portanto, o servidor não conseguia alcançar meu servidor OAuth2 localhost. Colocar nosso servidor OAuth2 atrás de um domínio resolveu o problema.

Agora, consigo conectar usuários existentes, mas não entendo como registrar novos usuários através deste plugin.
Se o usuário se registra com OAuth, ele recebe um erro dizendo que não possui uma conta ativa no servidor Discourse. O que é normal, pois é um novo usuário.

Existe um callback dedicado para registrar o usuário em vez de fazer login? Ou um parâmetro específico para definir para permitir a criação de conta?

Meu servidor OAuth da empresa estava gerando uma resposta JSON /profile com um pequeno erro de digitação em um campo. Tudo ficou bem depois de corrigir o erro de digitação.
Mas tenho que dizer que os logs do Discourse podem ser muito enganosos! Não havia nada de errado com o callback.

Olá equipe,

Estou tendo um problema para extrair o ID que preciso para minha solicitação JSON de usuário da resposta de autorização. Ao ler a documentação, parece que o ID da conta é enviado em um array aninhado:

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

Tentei definir o caminho do ID do usuário de retorno de chamada oauth2 como permissions[0].accountId, mas o valor do meu uid está sempre em branco. Infelizmente, as chamadas para extrair o JSON do usuário exigem esse accountId na URL JSON.

Consegui fazer isso funcionar passando permissions.first.accountId. Descobri que, ao passar permissions para uma propriedade de teste, a matriz já era analisada como uma matriz Ruby. Infelizmente, os campos parecem rejeitar a sintaxe Ruby para chamar elementos de matriz e qualquer tentativa de usar a sintaxe JavaScript resultaria em um TypeError String to Integer. Felizmente, Ruby tinha a sintaxe acima, este é o método pretendido?

Consegui fazer isso funcionar com o Authentik OAuth2, no entanto, houve alguns soluços com a configuração oauth2 user json url. Usei o endpoint user_info do Authentik para isso (/application/o/userinfo/), mas não sabia como mapear os campos. Para quem estiver procurando como configurar o Discourse com o OAuth2 do Authentik, aqui está o resumo:

  • Caminho do ID do usuário: preferred_username
  • Caminho do nome de usuário: preferred_username
  • Caminho do nome: name
  • Caminho do e-mail: email
  • Caminho do e-mail verificado: email_verified
  • Avatar: vazio.

Tive os seguintes problemas:

  1. No início, esqueci a barra final na URL JSON https://DOMAIN/application/o/userinfo/. Isso levou a solicitação de informações do usuário (link permanente para a origem) a retornar um código HTTP 301, o que causou falha no login. Não sei se a barra final deveria estar lá por especificação, mas talvez fosse bom lidar corretamente com o 301.
  2. Depurar isso acabou sendo complicado. As configurações de oauth2 debug auth foram uma salvação, mas… O Logster trunca o log de depuração antes de realmente despejar os dados de resposta significativos. Tive que modificar manualmente no contêiner a linha de log para
    log("user_json_response: #{user_json_response.status} #{user_json_response.headers} #{user_json_response.body}")
    
    Talvez essa linha de log pudesse ser atualizada? Acho que poderia ajudar outras pessoas a descobrir o caminho dos atributos JSON.
4 curtidas

Acabei de configurar o Auth0 com o plugin e descobri que os avatares não estão sendo capturados.

Estas são as configurações 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

No log de depuração, posso ver que o elemento picture está definido na resposta JSON, mas o avatar do usuário não muda, nem para usuários novos nem para os existentes.

O que eu perdi?

Qual é a melhor maneira de substituir o ícone no botão de login por outro ícone ou imagem?

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

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

parece suficiente, mas um pouco improvisado.

2 curtidas

Parece que o plugin só atualiza o avatar/nome de usuário na criação inicial do usuário, não toda vez que ele faz login.

Existe alguma maneira de corrigir isso e fazer com que o plugin também atualize o avatar no login/reconexão?

Você pode usar as configurações auth overrides email, auth overrides username e auth overrides name para fazer com que essas coisas se apliquem em logins futuros. Receio que atualmente não tenhamos uma configuração semelhante para avatares, mas seria pr-welcome

2 curtidas

Obrigado! Na verdade, encontrei estes mais tarde. Eu fiz um fork do repositório e adicionei minhas próprias versões para fazê-lo funcionar com o Roblox, o que incluiu a substituição para avatares. Que eu acredito que apenas usa a substituição de avatar do DiscourseConnect para que as pessoas não possam alterá-la.

Uma coisa que eu gostaria, no entanto, é que o Roblox não forneça um e-mail no OAuth, então, infelizmente, preciso que eles se inscrevam com um e-mail. Mas isso não é um problema para vocês, haha.

Uma postagem foi dividida em um novo tópico: Login do Twitter não funciona no meta

Alguém sabe se isso ainda funciona?

Sim. Tenho certeza de que este plugin funciona. :+1:

1 curtida

Olá, consegui integrar este plugin no meu discourse discuss.frontendlead.com, estou usando teachable oauth https://docs.teachable.com/docs/oauth-quickstart-guide

No entanto, eu só quero permitir que as pessoas se registrem com sucesso se e somente se elas tiverem uma conta paga atual no teachable. Eu imaginaria que preciso adicionar funcionalidade personalizada no plugin para lidar com isso? Estou me perguntando, vocês ou mesmo eu podemos introduzir outro campo nas configurações chamado código personalizado após o oauth, que permite aos desenvolvedores realizar ações específicas após o cadastro? Ou se houver melhores sugestões, por favor, me avisem.

Editar: Eu fiz um fork do repositório e consegui fazer funcionar aqui:

Se alguém mais usando teachable estiver tentando fazer o mesmo, meu repositório funcionará imediatamente, a única coisa é que se você não comprou um curso, ele dirá que você precisa ir ao meu domínio para comprá-lo. você pode querer atualizar isso para o seu próprio caso de uso.

2 curtidas

Isso é ótimo!

Há uma situação semelhante com o registro OAuth2 no plugin Discourse Patreon. Quando o “Login com Patreon” está habilitado, ele permite que qualquer pessoa com uma conta Patreon se registre no site Discourse. O que os proprietários de sites geralmente querem é permitir que apenas seus apoiadores possam registrar contas no Discourse. Eu me pergunto se os detalhes são retornados do Patreon que permitiriam adicionar uma lógica semelhante à autenticação do Patreon?

1 curtida

Tenho exatamente o mesmo erro que @qlands acima.

Meu plano inicial era enviar as informações do perfil no token. Vendo que não funcionou, reduzi a indentação para tentar a abordagem JSON. Mas ele nem chega ao ponto de chamar o arquivo JSON.

A mensagem de erro é:

(oauth2_basic) Falha na autenticação! credenciais inválidas: OAuth2::Error, {
  "access_token":"fa79b6fe0763862f5a8fd8",
  "token_type":"Bearer",
  "expires_in":3600,
  "scope":"profile"
}

Você vê algo de errado com a resposta acima?
Por que o plugin geraria um erro de credenciais inválidas enquanto o servidor OAuth2 respondeu com um 200 com um token?