discord activities | discord authenticate instances | | Search

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.

Run example

npm run import -- "discord express token endpoint"

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

What the code could have been:

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

Function Purpose

The getToken function is an asynchronous handler that retrieves an access token for Discord API using the client credentials flow.

Function Parameters

Function Steps

  1. Send Client Credentials Request
  2. Check for Launch and Frame IDs
  3. Store User Information
  4. Set Cookies
  5. Return Response

Notes