So currently it works, you get sent to roblox you agree but when you get sent back no data is given.
app.get('/redirect', async (req, res) => {
const code = req.query.code;
const state = req.query.state;
try {
// Validate input
if (!code || !state) {
return res.status(400).send('Invalid request: Missing code or state.');
}
// Find the corresponding database record
const data = await database.Schemas.oauth.findOne({ statecode: state }).exec();
if (!data) {
return res.status(404).send('State not found.');
}
const user = await client.users.fetch(data.discordID);
if (!user) {
return res.status(404).send('User not found.');
}
res.status(200).send('You may close this tab now.');
// Exchange authorization code for an access token
const params = new URLSearchParams({
client_id: process.env.ROBLOX_CLIENT_ID,
client_secret: process.env.ROBLOX_SECRET,
grant_type: 'authorization_code',
code: code,
});
const tokenResponse = await axios.post('https://apis.roblox.com/oauth/v1/token', params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});
if (tokenResponse.status !== 200) {
throw new Error('Failed to exchange authorization code for access token.');
}
const access_token = tokenResponse.data.access_token;
// Fetch user info from Roblox API
const userInfoResponse = await axios.get('https://apis.roblox.com/oauth/v1/userinfo', {
headers: { Authorization: `Bearer ${access_token}` },
});
if (userInfoResponse.status !== 200) {
throw new Error('Failed to fetch user info from Roblox API.');
}
const userInfo = userInfoResponse.data;
// Update database
data.verified = true;
data.robloxID = userInfo.sub;
data.robloxUsername = userInfo.preferred_username;
data.statecode = null;
await data.save();
// Update user's nickname in the Discord server
const guild = client.guilds.cache.get(process.env.GUILD_ID);
const member = await guild.members.fetch(user.id);
if (member && member.id !== guild.ownerId) {
await member.setNickname(userInfo.preferred_username);
}
// Notify verification channel
const successEmbed = new discord.MessageEmbed()
.setColor('GREEN')
.setDescription(`Successfully verified ${user.tag}!`)
.setTimestamp()
.setFooter({ text: 'Success!' });
client.channels.cache.get(process.env.VERIFICATION_CHANNEL).send({ embeds: [successEmbed] });
} catch (err) {
console.error('Error during verification:', err.message);
const errorEmbed = new discord.MessageEmbed()
.setColor('RED')
.setDescription('An error occurred during the verification process.')
.setTimestamp()
.setFooter({ text: 'Error!' });
client.channels.cache.get(process.env.VERIFICATION_CHANNEL).send({ embeds: [errorEmbed] });
res.status(500).send('An error occurred during the verification process.');
}
});
app.get('/discord/:discordid', async (req, res) => {
const discordid = req.params.discordid;
try {
const data = await database.Schemas.oauth.findOne({ discordID: discordid }).exec();
if (!data) {
return res.status(404).send({ verified: false });
}
res.status(200).send({
robloxID: data.robloxID,
robloxUsername: data.robloxUsername,
verified: data.verified,
});
} catch (err) {
console.error('Error fetching user data:', err.message);
res.status(500).send('An error occurred while fetching user data.');
}
});
Code for the redirect end
Here is my code for the bot command
const mongoose = require("mongoose");
const { Command, CommandOptionsRunTypeEnum } = require('@sapphire/framework');
const { Time } = require('@sapphire/time-utilities');
const { MessageEmbed, MessageButton, MessageActionRow } = require('discord.js');
// Define the schema
const UserSchema = new mongoose.Schema({
robloxID: { type: String, required: false, default: null },
discordID: { type: String, required: false, default: null },
verified: { type: Boolean, required: false, default: false },
statecode: { type: String, required: false, default: null },
robloxUsername: { type: String, required: false, default: null },
});
// Create the model
const UserModel = mongoose.models.User || mongoose.model('User', UserSchema);
const RedirectUrl = encodeURIComponent(process.env.ROBLOX_REDIRECT_URL)
class VerifyCommand extends Command {
constructor(context, options) {
super(context, {
...options,
aliases: ['verify'],
description: 'Verify your Roblox account',
cooldownDelay: Time.Second * 5, // 5 second cooldown
runIn: CommandOptionsRunTypeEnum.GuildAny,
preconditions: [],
requiredClientPermissions: [],
});
}
async chatInputRun(interaction) {
const user = interaction.user;
// Defer the reply to avoid timeouts
await interaction.deferReply({ ephemeral: true });
try {
const data = await UserModel.find({ discordID: user.id }).exec();
if (data.length === 0) {
const newUser = new UserModel({
robloxID: null,
discordID: user.id,
verified: false,
statecode: null
});
await newUser.save();
const embed = new MessageEmbed()
.setTitle('Verification')
.setDescription('Click the button below to verify your Roblox account!')
.setColor('GREEN')
.setTimestamp()
.setFooter('Verification');
await interaction.editReply({ embeds: [embed], components: [], ephemeral: true });
} else {
const code = this.makeid(10);
data[0].statecode = code;
await data[0].save();
const embed = new MessageEmbed()
.setTitle('Verification')
.setDescription('Click the button below to verify your Roblox account!')
.setColor('GREEN')
.setTimestamp()
.setFooter('Verification');
const button = new MessageButton()
.setStyle('LINK')
.setLabel('Verify')
.setURL(`https://authorize.roblox.com/?client_id=${process.env.ROBLOX_CLIENT_ID}&response_type=Code&redirect_uri=https://api.scfabyssal.com/redirect&scope=openid+profile&state=${code}`);
const row = new MessageActionRow()
.addComponents(button);
await interaction.editReply({ embeds: [embed], components: [row], ephemeral: true });
}
} catch (err) {
console.error(err);
await interaction.editReply({
embeds: [{
color: 0xed3043,
title: 'Error',
description: 'An error occurred during the verification process.'
}]
});
}
}
makeid(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
registerApplicationCommands(registry) {
registry.registerChatInputCommand(
(builder) => builder.setName(this.name).setDescription(this.description),
{ behaviorWhenNotIdentical: 'OVERWRITE' }
);
}
}
module.exports = { VerifyCommand };