The getToken
function is an asynchronous handler that retrieves an access token for the Discord API using the client credentials flow, making a POST request to the oauth2/token
endpoint and storing user information in the INSTANCES
and SESSIONS
objects. The function returns the access token data as a JSON response, setting various cookies for user authentication and storing a random nonce for future commands.
npm run import -- "discord express token endpoint"
const {INSTANCES, SESSIONS} = importer.import("discord gateway")
const {request} = require('gaxios')
const qs = require('qs');
const {DEFAULT_API, SECRET, TOKEN, DEFAULT_APPLICATION} = importer.import("discord configuration")
var crypto = require('crypto')
async function getToken(req, res, next) {
//console.log(req.body)
let result = await request({
url: DEFAULT_API + 'oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
//'Authorization': 'Bot ' + TOKEN
},
data: qs.stringify({
client_id: DEFAULT_APPLICATION,
client_secret: SECRET,
grant_type: 'authorization_code',
code: req.body.code,
})
})
let expiry = new Date(Date.now() + result.data.expires_in)
if(typeof req.body['launch_id'] != 'undefined'
&& typeof req.body['frame_id'] != 'undefined')
{
let userResult = await request({
method: 'GET',
url: DEFAULT_API + `oauth2/@me`,
headers: {
'Authorization': 'Bearer ' + result.data.access_token
}
})
// TODO: group permissions
if(typeof INSTANCES[req.body['launch_id']] == 'undefined') {
INSTANCES[req.body['launch_id']] = []
}
INSTANCES[req.body['launch_id']].push([userResult.data.user.id, req.body['frame_id']])
console.log(INSTANCES)
// generate nonce for client to use on future commands to authenticate with our server quickly instead of relying on cookies
result.data.session_id = crypto.randomBytes(16).toString('hex')
SESSIONS[result.data.session_id] = userResult.data.user.id
res.cookie('discord_bot_session', userResult.data.user.id, {
path: '/.proxy/',
expires: expiry
})
res.cookie('discord_bot_frame', req.body['frame_id'], {
path: '/.proxy/',
expires: expiry
})
}
res.cookie('discord_bot_expiry', Date.now() + result.data.expires_in, {
path: '/.proxy/',
expires: expiry
})
res.setHeader('Content-Type', 'application/json')
return res.send(JSON.stringify(result.data))
}
module.exports = getToken
const axios = require('axios');
const qs = require('qs');
const crypto = require('crypto');
const { DEFAULT_API, SECRET, TOKEN, DEFAULT_APPLICATION } = require('./discord-configuration');
const { INSTANCES, SESSIONS } = require('./discord-gateway');
const MAX_COOKIE_EXPIRY = 8.64e+13; // 1 hour in milliseconds
async function getToken(req, res, next) {
try {
const { code } = req.body;
if (!code) {
return res.status(400).send({ error: 'Missing authorization code' });
}
const response = await axios.post(
`${DEFAULT_API}oauth2/token`,
qs.stringify({
client_id: DEFAULT_APPLICATION,
client_secret: SECRET,
grant_type: 'authorization_code',
code,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
const { expires_in, access_token } = response.data;
const expiry = new Date(Date.now() + expires_in);
const expiryMs = expiry.getTime();
if (expiryMs > MAX_COOKIE_EXPIRY) {
expiryMs = MAX_COOKIE_EXPIRY;
}
if (
req.body?.launch_id &&
req.body?.frame_id &&
typeof INSTANCES[req.body.launch_id]!== 'undefined'
) {
// Get user information
const userResponse = await axios.get(
`${DEFAULT_API}oauth2/@me`,
{
headers: {
Authorization: `Bearer ${access_token}`,
},
}
);
const { user } = userResponse.data;
const instance = INSTANCES[req.body.launch_id];
instance.push([user.id, req.body.frame_id]);
console.log(INSTANCES);
// Generate nonce for client to use on future commands
const sessionId = crypto.randomBytes(16).toString('hex');
SESSIONS[sessionId] = user.id;
res.cookie('discord_bot_session', user.id, {
path: '/.proxy/',
expires: expiry,
});
res.cookie('discord_bot_frame', req.body.frame_id, {
path: '/.proxy/',
expires: expiry,
});
}
res.cookie('discord_bot_expiry', expiryMs, {
path: '/.proxy/',
expires: expiry,
});
res.setHeader('Content-Type', 'application/json');
return res.send(JSON.stringify(response.data));
} catch (error) {
console.error(error);
return res.status(500).send({ error: 'Internal Server Error' });
}
}
module.exports = getToken;
Function Breakdown: getToken
The getToken
function is an asynchronous handler that retrieves an access token for Discord API using the client credentials flow.
req
: The HTTP request objectres
: The HTTP response objectnext
: The next middleware function in the request response chainoauth2/token
endpointlaunch_id
and frame_id
oauth2/@me
endpointINSTANCES
objectSESSIONS
objectdiscord_bot_session
: User IDdiscord_bot_frame
: Frame IDdiscord_bot_expiry
: Expiration time of the access tokenapplication/json
gaxios
library to make HTTP requestsqs
library is used to stringify form datacrypto
library is used to generate a random nonceimporter
library is used to import external configuration and data