# 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