I have made a Discord-Roblox verification system using express.js. This can be counted as my second time working with web APIs, so I’m not sure if my code will work without any bugs/problems/etc.
The system works as follows:
- You enter a slash command with your username as an option;
- The bot stores your verification code and username inside a discord.js collection;
- After that, the bot sends an embed with the code;
- When you enter the code inside the game, it will send a GET request to the /verify endpoint.
That’s a rough explanation of how this system works.
Now, here’s the JavaScript part of it:
module.exports = function(app, client) {
const route = app.route("/verify");
route.get(function(req, res) {
const key = req.headers["api-token"];
const username = req.headers.name;
const code = req.headers.code;
if (key == process.env["verify-secret"] && username && code) {
const entry = client.verifyList.find(e => e[0] == code && e[1] == username);
if (!entry) return res.send("The username or code did not match. Please try using the command again.");
client.verifyList.sweep(e => e[0] == code && e[1] == username);
const guild = client.guilds.cache.find(g => g.id == "901511567315730432");
const unverifiedRole = guild.roles.cache.find(r => r.id == "902641778014965811");
const memberRole = guild.roles.cache.find(r => r.id == "901515240699740171");
const member = guild.members.cache.find(m => m.id == entry[2]);
member.roles.remove(unverifiedRole);
member.roles.add(memberRole);
res.send("Your Discord account has been verified. Thank you for joining our community!");
} else {
res.sendStatus(403);
}
});
};
And this is the LUA part:
local secret = "" -- this is something like an API key for security
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local used, status = false, "none"
local function get(headers)
headers["api-token"] = secret
local success, response = pcall(function()
return HttpService:GetAsync("LINK", false, headers)
end)
status = success and (response:match("again") and "failed" or "success") or "failed"
if not success then
return "The GET request has failed with code: " .. response
else
return response
end
end
ReplicatedStorage.Verify.OnServerInvoke = function(player, code)
if type(code) == "string" and not used then
local code = code:gsub("%s+", "") -- %s also includes \n, \r, \t, \v, \f
if code ~= "" and #code <= 20 and #code >= 10 then
used = true
task.spawn(function()
repeat task.wait() until status ~= "none"
if status == "failed" then
task.delay(5, function()
player:Kick("Please try using the command again.")
end)
end
end)
return get({ name = player.Name, code = code })
end
end
end
Here’s what it looks like in-game:
PS: The verification game’s server size is set to 1.