<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vxrpenter</title>
    <description>The latest articles on Forem by Vxrpenter (@vxrpenter).</description>
    <link>https://forem.com/vxrpenter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3259189%2F44f52789-84e5-49fb-a461-f917abd53a9d.jpeg</url>
      <title>Forem: Vxrpenter</title>
      <link>https://forem.com/vxrpenter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vxrpenter"/>
    <language>en</language>
    <item>
      <title>Discord OAuth, hard to understand, easy to use</title>
      <dc:creator>Vxrpenter</dc:creator>
      <pubDate>Sat, 21 Jun 2025 16:20:43 +0000</pubDate>
      <link>https://forem.com/vxrpenter/discord-oauth-hard-to-understand-easy-to-use-1f33</link>
      <guid>https://forem.com/vxrpenter/discord-oauth-hard-to-understand-easy-to-use-1f33</guid>
      <description>&lt;h3&gt;
  
  
  Table Of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;What is OAuth&lt;/li&gt;
&lt;li&gt;
Using OAuth

&lt;ul&gt;
&lt;li&gt;Creating the OAuth Link&lt;/li&gt;
&lt;li&gt;Creating a simple WebServer&lt;/li&gt;
&lt;li&gt;Making the api requests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I once needed to connect users Discord accounts with their Steam accounts. So I just asked them to enter their SteamId and then connected them using a simple database table. I thought that was it, but then someone brought the fact to me, that people could enter someone else's SteamId to impersonate them and take actions in their account. So I tried finding a way to fix it and that lead me to my biggest coding nightmare, working with Discord OAuth.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is even OAuth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Cloudflare defines OAuth as follows: "OAuth is a technical standard for authorizing users. It is a protocol for passing authorization from one service to another without sharing the actual user credentials, such as a username and password" [&lt;a href="https://www.cloudflare.com/learning/access-management/what-is-oauth/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;We can compile this down to the following statement, "OAuth allows us to access certain information without credential sharing". For Discord this allows us to get account connections, guilds (Discord servers) or even E-Mails without the user having to provide their password. It should be self explanatory why this is useful but to boil it down, it allows us to interact with certain user information in a safe and private manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using OAuth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Let's look into OAuth from the problem described in the introduction. We need to connect a Discord UserId with a SteamId, so we need two different OAuth scopes. These are &lt;code&gt;identify&lt;/code&gt;, which allows us to use the &lt;code&gt;user/@me&lt;/code&gt; endpoint, for querying user profile information and the &lt;code&gt;connections&lt;/code&gt; scope, which gives us access to the &lt;code&gt;/users/@me/connections&lt;/code&gt; endpoint, which returns connections information.&lt;/p&gt;

&lt;p&gt;So what steps do we need now, that we know what information we need to query?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating the OAuth link&lt;/li&gt;
&lt;li&gt;Creating a simple WebServer for redirects&lt;/li&gt;
&lt;li&gt;Making the Api requests&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating the OAuth link &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The OAuth link, is generated by Discord and given to the user, for them to authorize the data transfer. It is really simple to create one, although you have to take some things into account.&lt;/p&gt;

&lt;p&gt;Firstly, navigate to the &lt;a href="https://discord.com/developers/applications" rel="noopener noreferrer"&gt;Discord Developer Portal&lt;/a&gt;, then click on your application and find the OAuth section. Here we need to add the redirect, that Discord will send the user to. In our case we will simply use a localhost:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l1dy61sh6kozmrhavms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l1dy61sh6kozmrhavms.png" alt="A field for entering redirects with the domain http://localhost:8080/discord/redirect/oauth inside it" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll select our scopes (&lt;code&gt;identify&lt;/code&gt; and &lt;code&gt;connections&lt;/code&gt;) in the URL generator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9839wirda6c3qmpyzr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9839wirda6c3qmpyzr3.png" alt="A lot of discord OAuth scope selectors, underneath the headline of " width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And at last, just select the redirect you entered previously and your URL will be shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2mw7sie9vudy2gp8833.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2mw7sie9vudy2gp8833.png" alt="A select field showing the redirect url http://localhost:8080/discord/redirect/oauth" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you provide a user with this link, they will be prompted with this popup. After clicking on authorize they will then be redirected to your page, allowing us to start using OAuth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p1eolwxyttv3igwv6gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p1eolwxyttv3igwv6gg.png" alt="A form showing that an application wants to access identification and connection information from the user, prompting them to cancel or authorize it" width="567" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a simple WebServer &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Oauth requests from Discord work in the following way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User authorizes through your OAuth link&lt;/li&gt;
&lt;li&gt;Discord redirects them to your WebServer with an authorization code attached &lt;/li&gt;
&lt;li&gt;You send a request to discord to get an authorization token&lt;/li&gt;
&lt;li&gt;You query data using the token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It sounds really simple and it is really simple, but it took way to long for me to understand this, so let's go through it step by step. We firstly create a simple WebServer for our OAuth redirect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;embeddedServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Netty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;routing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"discord/redirect/oauth"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we just have to search for the authorization code in the request parameters and maybe add a small response text (this code is in the get... section):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The redirect was successful, you can close this page now"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;authorizationCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queryParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making the api requests &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After receiving our authorization code, we still need to get the authorization token, to actually start querying user data. We'll start by creating a json decoder plus an Http-Client for our request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ignoreUnknownKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CIO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientContentNegotiation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need a data class that our json decoder can use for the serialization process (for other languages, use the best json decoding manner available):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;DiscordTokenResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"token_type"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tokenType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expires_in"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we'll create our request and send it using our created client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tokenCall&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://discord.com/api/oauth2/token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FormDataContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"grant_type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"authorization_code"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"redirect_uri"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At last we'll check for the request's success and then serialize our json output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;tokenCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tokenResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decodeFromString&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DiscordTokenResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bodyAsText&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have our lovely token. We can now use this token to firstly get our userId and a corresponding data class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;DiscordUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userCall&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://discord.com/api/users/@me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer ${tokenResponse.accessToken}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;userCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;discordUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decodeFromString&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DiscordUser&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;userCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bodyAsText&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we follow up with our connection request and the corresponding data class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;DiscordConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"friend_sync"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;friendSync&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"metadata_visibility"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;metadataVisibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"show_activity"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;showActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@SerialName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"two_way_link"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;twoWayLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;connectionCall&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://discord.com/api/users/@me/connections"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer ${tokenResponse.accessToken}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;connectionCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decodeFromString&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DiscordConnection&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bodyAsText&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our values, we can simply connect them, completing our little OAuth adventure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Discord OAuth, or OAuth in general does take a bit to get used to, but isn't as complicated as I once thought. I had a lot of problems with it, when I first tried to use it and needed help by other developers to do so. But after a lot of time and stress I finally understood it. The thing I learned from this, you just have to try over and over until you succeed.&lt;/p&gt;

&lt;p&gt;This was more of a tutorial article, hope that it was still somewhat entertaining and informational. The examples are in Kotlin, but the general structure can be applied to all languages. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The cover image was taken from discord's official &lt;a href="https://discord.com/branding" rel="noopener noreferrer"&gt;branding page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Definition of OAuth was taken from this &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-oauth/" rel="noopener noreferrer"&gt;Cloudflair Article&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Information from this &lt;a href="https://de.wikipedia.org/wiki/OAuth" rel="noopener noreferrer"&gt;German Wikipedia Article&lt;/a&gt; was also used for research&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://discord.com/developers" rel="noopener noreferrer"&gt;Discord Developer Docs&lt;/a&gt; were used for the endpoint and OAuth information&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discord</category>
      <category>oauth</category>
      <category>kotlin</category>
      <category>learning</category>
    </item>
    <item>
      <title>What 1 year of Discord Bot Development taught me</title>
      <dc:creator>Vxrpenter</dc:creator>
      <pubDate>Sat, 21 Jun 2025 14:24:52 +0000</pubDate>
      <link>https://forem.com/vxrpenter/what-1-year-of-discord-bot-development-taught-me-5gen</link>
      <guid>https://forem.com/vxrpenter/what-1-year-of-discord-bot-development-taught-me-5gen</guid>
      <description>&lt;h3&gt;
  
  
  Table Of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Replying and RestAction Failure&lt;/li&gt;
&lt;li&gt;Always do extra work on Embeds&lt;/li&gt;
&lt;li&gt;Use Configuration&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When starting to develop Discord bots, I knew nothing about it. I even had problems getting the bot online, because I didn't understand how token's worked. It took me a embarrassingly long time to understand some of the quirks and functions of the discord API, and me being relatively new to the coding space didn't help a bit. I want to share some of my experiences and a bit of corresponding advice with other developers, to lessen their suffering or for you to laugh at my issues xD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replying and RestAction failure &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When working with any sort of event (buttons, modals etc.), you have to reply to it any form, be it a message, an edit, or just a defer. But often I did something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ButtonInteractionEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;SomeLongExecutingFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A peculiar message"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This always caused an &lt;code&gt;ErrorResponseException&lt;/code&gt;, which then halted the whole event's process and broke several functions. It took me long to understand why this was happening until I read the error message which stated that "[t]his interaction took longer than 3 seconds to be acknowledged", which then brought me to the realization that what I was doing was stupid and redundant.&lt;/p&gt;

&lt;p&gt;So after testing a bit and reading around 100 StackOverflow posts, I found the most simple solution to this was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ButtonInteractionEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deferReply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nc"&gt;SomeLongExecutingFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A peculiar message"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This simply prompts the user with a bot thinking message and gives the bot a longer time to wait before replying to a message. It's such a simple solution and makes me question my own IQ.&lt;/p&gt;
&lt;h2&gt;
  
  
  Always do extra work on Embeds &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When firstly starting to work with Embeds, I did only the most minimal work, in styling them, as possible. I thought that it would look good either way, but they often turned out as something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;embed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Embed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlg8d8xefrv1u7x7rcjy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlg8d8xefrv1u7x7rcjy.png" alt="A discord Embed with gray sidebar and lorem ipsum placeholder text, looking bland and boring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some time I decided to put in some extra work to make them look better, which taught me some good advice.&lt;/p&gt;

&lt;p&gt;1‎.‎ ‎Some color can make a huge difference. It doesn't have to be the most vibrant color, but even a slight red tone, can make an Embed look so much better:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;embed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Embed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xE74D3C&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5hku1vq5wvbtt3mgcpw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5hku1vq5wvbtt3mgcpw.png" alt="A discord Embed with red sidebar and lorem ipsum placeholder text that looks way more vibrant than the one before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2‎.‎ When a message is about a single user, or references them in a particular way, always try using mentions and thumbnails/author. It makes makes the message stand out more and gives it a personal vibe:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;embed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Embed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xE74D3C&lt;/span&gt;
    &lt;span class="nf"&gt;author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;globalName&lt;/span&gt;
        &lt;span class="n"&gt;iconUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;" Lorem ipsum dolor sit amet, ${event.user.asMention}. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35eqhg6st9zggbz2pvge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35eqhg6st9zggbz2pvge.png" alt="A discord Embed with red sidebar and lorem ipsum placeholder text and an author labled as Vxrpenter with his profile picture on the left side"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or the same thing with the bigger thumbnail:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;embed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Embed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xE74D3C&lt;/span&gt;
    &lt;span class="n"&gt;thumbnail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;" Lorem ipsum dolor sit amet, ${event.user.asMention}. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqy23slh1jio68enhy5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqy23slh1jio68enhy5i.png" alt="A discord Embed with red sidebar and lorem ipsum placeholder text and the a thumbnails resembling the authors profile picture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Use Configuration &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This is a thing I realized fairly fast, but still took some time to really internalize. There are many values you need to enter into your bot e.g. token, secret, activity, messages, embed content etc. It is a bit of a hustle to make all of that configurable but it will pay off in the end. As an example look at these two snippets of code, which one looks cleaner?:&lt;/p&gt;

&lt;p&gt;First the one without any configurable values &lt;em&gt;(configurable meaning not editing the code itself but something like a &lt;code&gt;config.yml&lt;/code&gt; that holds the values)&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;light&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mySuperSecretToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enableCoroutines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PLAYING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/help"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the second one with configuration:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;light&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enableCoroutines&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PLAYING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;takeIf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;enumContains&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ActivityType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nc"&gt;ActivityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityContent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At first glance, the second one seems more complicated but that just comes from the handling of probable miss-configurations, by providing a base value for the activity type that is used when the config value is missing or configured incorrectly.&lt;/p&gt;

&lt;p&gt;But this provides so much value to normal users, or even for yourself as the developer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is easy to change these values whenever you like.&lt;/li&gt;
&lt;li&gt;When you are working with longer compile times (e.g. Docker Images), it can make your work so much faster&lt;/li&gt;
&lt;li&gt;You don't have your token in the compiled program&lt;/li&gt;
&lt;li&gt;You are able to easily share the project/make it open source without having to search through your code for secret values&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then we have an example for a normal text reply, either you use a hard-coded solution like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget. "&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or you can just create a special translation configuration that stores all of these texts:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lipsum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textPlaceholder&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It even opens up the possible implementation of multi language support, by just creating multiple translation files e.g. &lt;code&gt;en_US&lt;/code&gt;, &lt;code&gt;en_UK&lt;/code&gt;, &lt;code&gt;de_DE&lt;/code&gt; etc. and then just using a single &lt;a href="https://www.geeksforgeeks.org/java/serialization-and-deserialization-in-java/" rel="noopener noreferrer"&gt;Serializer&lt;/a&gt; to convert all of these files to the same usable format.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;These are just some of the things I learned while developing Discord bots, but they are the most significant ones. I hope that you somehow enjoyed reading this article and hopefully were able to learn something from it. As this is my first article ever, I would appreciate some constructive criticism (btw. english is not my mother tongue so I'm sorry for any language mistakes).&lt;/p&gt;

&lt;p&gt;If you want to check out some of my work, you can look at my &lt;a href="https://github.com/Vxrpenter" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or the project were I implemented all of this/learned it:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Vxrpenter" rel="noopener noreferrer"&gt;
        Vxrpenter
      &lt;/a&gt; / &lt;a href="https://github.com/Vxrpenter/SCPToolsBot" rel="noopener noreferrer"&gt;
        SCPToolsBot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ⚡ A discord bot application for usage on SCP: Secret Laboratory servers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/110356385/447672775-17f20ab2-679d-4a28-a151-10ae112f6998.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzQ2NDk5MjQsIm5iZiI6MTc3NDY0OTYyNCwicGF0aCI6Ii8xMTAzNTYzODUvNDQ3NjcyNzc1LTE3ZjIwYWIyLTY3OWQtNGEyOC1hMTUxLTEwYWUxMTJmNjk5OC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwMzI3JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDMyN1QyMjEzNDRaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1hOWNiMWI4OTU3OGZhYWZmNjMzNzVmM2MyYzg3YWIxM2UzZDg2ZWQxODhmNzMyYjc3NTVkMGQzNTM1Nzk0ZjE0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.F7730p93wpNF_Md2P3Ksy0tQvbK5B_-HQcJU3VlcQWE"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F110356385%2F447672775-17f20ab2-679d-4a28-a151-10ae112f6998.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzQ2NDk5MjQsIm5iZiI6MTc3NDY0OTYyNCwicGF0aCI6Ii8xMTAzNTYzODUvNDQ3NjcyNzc1LTE3ZjIwYWIyLTY3OWQtNGEyOC1hMTUxLTEwYWUxMTJmNjk5OC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwMzI3JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDMyN1QyMjEzNDRaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1hOWNiMWI4OTU3OGZhYWZmNjMzNzVmM2MyYzg3YWIxM2UzZDg2ZWQxODhmNzMyYjc3NTVkMGQzNTM1Nzk0ZjE0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.F7730p93wpNF_Md2P3Ksy0tQvbK5B_-HQcJU3VlcQWE" width="200" height="200"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SCPToolsBot&lt;/h1&gt;
&lt;/div&gt;

&lt;div&gt;
  &lt;a href="https://github.com/Vxrpenter/SCPToolsBot/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d2ee23f8862a463f0120e90193f748ca78575976cfe9e91e1aa4ce7892c8f691/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f56787270656e7465722f534350546f6f6c73426f743f696e636c7564655f70726572656c6561736573266c6f676f3d676974687562266c6f676f53697a653d616d67266c6f676f436f6c6f723d613734303430266c6162656c436f6c6f723d33333338333426736f72743d6461746526646973706c61795f6e616d653d746167267374796c653d666f722d7468652d6261646765266c6162656c3d4c415445535425323052454c4541534526636f6c6f723d613734303430"&gt;&lt;/a&gt; 
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9b5e0d8f27a6c3ebf24d2c23d4e99655abf05cb1037b676d513eee16351c53c5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f56787270656e7465722f534350546f6f6c73426f742f746f74616c3f7374796c653d666f722d7468652d6261646765266c6f676f3d676974626f6f6b266c6f676f53697a653d616d67266c6162656c3d446f776e6c6f616473266c6162656c436f6c6f723d333333383334266c6f676f436f6c6f723d61373430343026636f6c6f723d613734303430"&gt;&lt;img src="https://camo.githubusercontent.com/9b5e0d8f27a6c3ebf24d2c23d4e99655abf05cb1037b676d513eee16351c53c5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f56787270656e7465722f534350546f6f6c73426f742f746f74616c3f7374796c653d666f722d7468652d6261646765266c6f676f3d676974626f6f6b266c6f676f53697a653d616d67266c6162656c3d446f776e6c6f616473266c6162656c436f6c6f723d333333383334266c6f676f436f6c6f723d61373430343026636f6c6f723d613734303430"&gt;&lt;/a&gt; 
  &lt;a href="https://hub.docker.com/r/vxrpenter/scptoolsbot" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97a8fa957fef8e241f66516bbfb48fbfad14b4fc57080f7fff913e32af620aa9/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f76787270656e7465722f736370746f6f6c73626f743f7374796c653d666f722d7468652d6261646765266c6f676f3d646f636b6572266c6f676f53697a653d616d67266c6162656c3d446f636b657225323050756c6c73266c6162656c436f6c6f723d333333383334266c6f676f436f6c6f723d61373430343026636f6c6f723d613734303430"&gt;&lt;/a&gt;  &lt;a href="https://github.com/Vxrpenter/SCPToolsBot/issues" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4c1432be6154012a668a8555097125e8a1892e118a0681de33db2740adf7c118/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f56787270656e7465722f534350546f6f6c73426f743f7374796c653d666f722d7468652d6261646765266c6f676f3d676974266c6f676f53697a653d616d67266c6162656c3d497373756573266c6162656c436f6c6f723d333333383334266c6f676f436f6c6f723d61373430343026636f6c6f723d613734303430"&gt;&lt;/a&gt; &lt;a href="https://github.com/Vxrpenter/SCPToolsBot/pulls" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4f0168e41e2fe83b240fc7de3414e9f6cedc4d6feed4097bf9296dd22c36cf4a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732d70722d7261772f56787270656e7465722f534350546f6f6c73426f743f7374796c653d666f722d7468652d6261646765266c6f676f3d676974266c6f676f53697a653d616d67266c6162656c3d50756c6c2532305265717565737473266c6162656c436f6c6f723d333333383334266c6f676f436f6c6f723d61373430343026636f6c6f723d613734303430"&gt;&lt;/a&gt;  &lt;a href="https://github.com/Vxrpenter/SCPToolsBot/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/50e03940e3be2d59e54058945f7ab278878d86db479a15d443aebd8608b434f9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f56787270656e7465722f534350546f6f6c73426f743f7374796c653d666f722d7468652d6261646765266c6f676f3d616d617a6f6e69616d266c6f676f53697a653d616d67266c6f676f436f6c6f723d613734303430266c6162656c3d4c6963656e636564253230556e646572266c6162656c436f6c6f723d33333338333426636f6c6f723d613734303430"&gt;&lt;/a&gt; 
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is ScpToolsBot&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;ScpTools Bot is an application
to enhance your Scp Secret Laboratory server
by providing quality-of-life features in combination with moderation and team management tools
It also integrates with plugins like cedmod
to build on already existing infrastructure and to use features they offer.&lt;/p&gt;
&lt;p&gt;For more information check out the &lt;a href="https://override.gitbook.io/scptoolsbot" rel="nofollow noopener noreferrer"&gt;wiki&lt;/a&gt; or join the discord:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://discord.gg/cAXU9Y7T9a" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b9c9d6f0227a6549bc173032d801fe0fd0295e5e6e235c7e6155c05cbc961f15/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d2532333538363546322e7376673f266c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465" width="120" height="35"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What Features are included&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What is this&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fully customizable translation&lt;/td&gt;
&lt;td&gt;All text can be changed to anything you can imagine, there are even color codes and other utility functions for even more customizability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration options&lt;/td&gt;
&lt;td&gt;Many features can be changed to personal liking, e.g. disabling a certain part of it or enabling something else that is not active by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status bot cluster&lt;/td&gt;
&lt;td&gt;A cluster of bots that show the player count of your server. They also send connection messages to a channel that was configured by the sysadmin, that show&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Vxrpenter/SCPToolsBot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Sources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The cover image was taken from discord's official &lt;a href="https://discord.com/branding" rel="noopener noreferrer"&gt;branding page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The placeholder text has been taken from the &lt;a href="https://www.lipsum.com/" rel="noopener noreferrer"&gt;Lipsum page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The code examples were written in kotlin using the &lt;a href="https://github.com/discord-jda/JDA" rel="noopener noreferrer"&gt;JDA&lt;/a&gt; and &lt;a href="https://github.com/MinnDevelopment/jda-ktx" rel="noopener noreferrer"&gt;jda-jtx&lt;/a&gt; libraries&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discord</category>
      <category>kotlin</category>
      <category>java</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
