discourse/lib/auth/discord_authenticator.rb

81 lines
2.2 KiB
Ruby

# frozen_string_literal: true
class Auth::DiscordAuthenticator < Auth::ManagedAuthenticator
class DiscordStrategy < OmniAuth::Strategies::OAuth2
option :name, "discord"
option :scope, "identify email guilds"
option :client_options,
site: "https://discord.com/api",
authorize_url: "oauth2/authorize",
token_url: "oauth2/token"
option :authorize_options, %i[scope permissions]
uid { raw_info["id"] }
info do
{
name: raw_info["username"],
email: raw_info["verified"] ? raw_info["email"] : nil,
image: "https://cdn.discordapp.com/avatars/#{raw_info["id"]}/#{raw_info["avatar"]}",
}
end
extra { { "raw_info" => raw_info } }
def raw_info
@raw_info ||=
access_token
.get("users/@me")
.parsed
.merge(guilds: access_token.get("users/@me/guilds").parsed)
end
def callback_url
full_host + script_name + callback_path
end
end
def name
"discord"
end
def enabled?
SiteSetting.enable_discord_logins?
end
def register_middleware(omniauth)
omniauth.provider DiscordStrategy,
setup:
lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.discord_client_id
strategy.options[:client_secret] = SiteSetting.discord_secret
}
end
def after_authenticate(auth_token, existing_account: nil)
allowed_guild_ids = SiteSetting.discord_trusted_guilds.split("|")
if allowed_guild_ids.length > 0
user_guild_ids = auth_token.extra[:raw_info][:guilds].map { |g| g["id"] }
if (user_guild_ids & allowed_guild_ids).empty? # User is not in any allowed guilds
return(
Auth::Result.new.tap do |auth_result|
auth_result.failed = true
auth_result.failed_reason = I18n.t("discord.not_in_allowed_guild")
end
)
end
end
super
end
# the `info` block above only picks the email from Discord API if it's verified
def primary_email_verified?(auth_token)
true
end
end