Knowledge Base

/

Security

Update

How we protect your bot token

A straightforward look at where we keep your bot token, how it's stored, and how far we protect it.

BotShade Team
BotShade Team

|

8 min read

|

Last updated: June 15, 2026

When you use BotShade, the thing you probably care about most is your bot token. If it leaks, your bot can be hijacked and your server can be wrecked. So we want to be straightforward about where we keep it, how it’s stored, how far we protect it — and what we’ve decided not to do.

Security writing tends to turn into a dry list of conclusions. In this article we try to share the why behind each design decision as well.

In this article:

What a bot token is, exactly

A bot token is a long string Discord hands you when you create a bot in the Developer Portal. It’s how a bot identifies itself to Discord — effectively, a password that belongs to the bot itself.

Anyone holding the token can do anything the bot is allowed to do: send messages, assign roles, ban members, change server settings — all of it, within the bot’s permissions. That’s why the token is called out as the single most sensitive piece of information for any Discord bot.

Using a bot platform like BotShade means handing this token to a service. Wanting to know what happens to it, and how it’s protected, is a completely fair thing to ask.

What happens when you hand it to us

The moment you paste the token into the dashboard and hit save, the following happens, in order:

  1. The token is sent from your browser to BotShade over a TLS-encrypted connection.
  2. Server-side, we make a one-time call to the Discord API to verify that the token is valid and to learn which bot it belongs to.
  3. Once verified, the token is immediately encrypted with AES-256-GCM and written to the database.
  4. The key needed to decrypt it lives in a separate location — a cloud secret manager — kept isolated from the database.
  5. Any plaintext token that lived briefly in memory is discarded as soon as the request is done.

The string of dots you see in the input box can’t be recovered after saving. What the dashboard shows from that point on is only the minimum needed for you to recognize which bot it is — typically the last four characters.

How it’s stored

Every bot token in our database is encrypted with AES-256-GCM. AES-256-GCM is an authenticated encryption scheme, which means encryption and tamper detection are built into the same construction: it both makes the data unreadable and lets us tell if anyone has altered it.

The key needed to decrypt it lives in a separate cloud secret manager. The key itself is configured to be reachable only from a specific, narrowly-scoped operational surface.

So even with a database dump in hand, a token can’t be decrypted from that alone. The plaintext is only recoverable when an attacker holds both the ciphertext and the key-side access — which is the textbook shape of defense in depth: if one layer falls, the next one still holds.

Under the hood: AES-256-GCM, authentication tags, and nonces

The “GCM” in AES-256-GCM stands for Galois/Counter Mode, which produces a short MAC called an authentication tag alongside the encrypted output. On decryption, the tag is verified, and a single bit flipped in the ciphertext or associated data causes decryption to fail outright. That’s how a single primitive handles both “make it unreadable” and “check whether it has been altered.”

GCM requires a unique nonce (“number used once”) per record. Reusing a nonce under the same key catastrophically weakens the cipher, so each record carries its own non-colliding nonce by construction.

We also use AAD (Additional Authenticated Data) to bind extra context — for example, which bot the ciphertext belongs to — into the authentication tag. Any attempt to swap a token from one bot’s record into another’s is caught at decryption, not after the fact.

How bots stay separated

BotShade runs many users’ bots through the same database. The property that matters here is that bot A can never reach bot B’s token.

We enforce this at the database layer with PostgreSQL Row Level Security (RLS). RLS lets you declare “which rows are visible to whom” as a database policy and applies it automatically on every query. Even if the application code makes a mistake, the database itself rejects the query: “you only get rows that belong to your bot.”

The reason we put this at the database layer, rather than the application layer, is that we want to design out the possibility of a bug or a rushed release accidentally exposing another bot’s data. Application code changes every day; database policies almost never do. It’s safer to put the load-bearing safety guarantee on the slower-moving floor.

A composite primary key is layered on top so that the very shape of a cross-bot query is structurally not a valid query at all.

Under the hood: how Row Level Security works

PostgreSQL Row Level Security is a feature that lets you declare, per table, “which rows are visible to which actor,” as a policy on the database side. On every request, the application tells the database who the current bot is, through a safe path, and the policy is woven into the query automatically.

Even if the application code issues what looks like a full-table query, the database silently appends “only the rows that belong to the current bot.” That’s the value of putting the separation at the database layer rather than the application layer.

On top of that, the DB role the application connects with isn’t granted the privilege needed to bypass row-level policies. “You cannot accidentally turn the policy off” is the default state of the system, not something we have to remember to enforce on every change.

How we protect it in transit

There are roughly three paths the token travels on:

  • Browser ↔ the BotShade dashboard
  • BotShade ↔ Discord
  • Between our internal services

All of them are encrypted with TLS. The front door is fronted by Cloudflare, with SSL mode set to Full (Strict). “Full (Strict)” means the leg between Cloudflare and our origin servers — invisible to the visitor — is also protected by a valid certificate. There is no opportunity to silently degrade to HTTP and leak something.

At the edge, WAF and DDoS Protection are enabled, so obviously bad requests are dropped before they reach the application. On top of that, important API requests carry an HMAC signature, which we verify on every request server-side, to confirm both the sender and that nothing has been tampered with in flight.

Eavesdropping, impersonation, and tampering each get their own layer of protection, applied at the same time but at different layers.

Under the hood: HMAC signing and replay protection

Important API requests carry an HMAC-SHA256 signature derived from a shared secret. The client computes a signature over the key parts of the request — method, path, body, timestamp — and the server re-computes the same value on its side. If the two don’t match, the request is rejected immediately.

Signing keys are rotatable, with old and new keys accepted in parallel for a brief overlap window. That way, if a key is suspected of being exposed, we can swap it out without stopping the service.

Replay attacks — where an attacker resends a legitimate request verbatim — are addressed by signing the timestamp as part of the payload and rejecting any request whose timestamp is older than a fixed window. When needed, we layer a short-lived nonce on top to reject the second copy of the same request even within that window.

Who can touch the token

Straight answer: we don’t reach for the decrypted token. The decryption path isn’t wired into our day-to-day operations at all, so dashboard development and support work simply don’t sit in front of a plaintext token. We don’t want to, and we don’t.

What we may touch is the ciphertext itself — the encrypted blob as it lives in storage — for things like integrity checks and tamper detection. That’s about confirming “is this the same value, is it intact” without ever decrypting it. It’s not about reading the contents.

Whatever administrative operations are performed on the operations side are recorded in the audit log. Who did what, and when, stays there — currently retained for 7 days.

If something happens

There is no such thing as perfect defense. So what happens when something does go wrong matters just as much.

  • Suspicious access and unusual sign-in patterns are surfaced and reviewed.
  • If a token may have leaked, we notify the affected user.
  • You can regenerate your token from the dashboard at any time; the old one is invalidated immediately.
  • Security reports are accepted at help@botshade.com. We respond in good faith to every report made in good faith (see Responsible Disclosure).

We tell users about token regeneration as their “emergency exit.” If something feels off, the right first move is to regenerate and invalidate the old token — that alone stops the spread of damage in most scenarios.

Things we deliberately don’t do

A design is defined as much by what it refuses to do as by what it does. Some of the things we’ve explicitly decided not to do at BotShade:

  • We don’t write tokens to logs. Not in error logs, debug logs, metrics, or traces — not the token itself and not any substring of it.
  • We don’t ask for your token in support tickets or chats. We will never ask you to share your token with us for support purposes. If a message arrives asking you to do so, it isn’t from us.
  • We don’t display the token outside the dashboard. Not in email, not in a Discord message, not via any external integration. The plaintext token doesn’t leave the dashboard surface.
  • We don’t keep the decryption key resident on operational infrastructure. Access to the key is brokered narrowly, only when actually needed, rather than left available “just in case.”

These “things we don’t do” aren’t a paper policy. They are baked into both the code and the way we run operations.

What we can’t cover, and what we’d ask of you

We try to be honest about where our coverage ends. The following are things we can’t fully protect against on our side:

  • A user accidentally committing the token to a public repository.
  • A dashboard login account being taken over by a third party.
  • A user’s device itself being compromised by malware.

The best way to harden the second and third is to strengthen how you sign in to the dashboard. The BotShade dashboard has no password of its own — you sign in with an external account (Discord, Google, and so on), or with a passkey.

So what we’d ask of you is:

  • Enable two-factor authentication (2FA) on the account you sign in with — Discord, Google, etc. Since BotShade has no password itself, the strength of the front door is whatever the strength of that linked account is.
  • If you can, register a passkey. Passkeys are bound to the device and are resistant to phishing.

For the first risk (accidentally committing a token to a public repository, and so on), the fastest response is to go to Discord’s Developer Portal and hit “Reset Token” — the old token is invalidated on the spot. Re-register the new one on the BotShade dashboard, and your bot keeps running.

Security doesn’t work as a one-sided effort. It only adds up to “minimum damage” when both sides — ours and yours — do their part. We will keep doing ours, honestly.

← Back to Knowledge Base