discord activities | discord client code | start activity server | Search

This code manages the Discord OAuth flow by exchanging a handshake message, authorizing the user, and fetching an access token to authenticate with the Discord API. It uses event listeners to respond to messages from the parent window, sending POST requests and authentication messages to complete the OAuth flow.

Run example

npm run import -- "discord client auth code"

discord client auth code


let expiry
let result
let initNonce = Math.round(Math.random() * 1000)

window.addEventListener('message', async (evt) => {

  document.querySelector('h1').innerHTML = '<pre>' + JSON.stringify(evt.data, null, 2) + '</pre>'

  const sourceWindow = () => {
    return (window.parent.opener || window.parent)
  }

  if(evt.data[0] == 3 && typeof evt.data[1].frame_id != 'undefined') {

    result = evt.data[1] // get it from page init instead of query params
    // send handshake
    sourceWindow().postMessage([0, {
      v: 1,
      encoding: 'json',
      client_id: '{CLIENT_ID}',
      frame_id: evt.data[1].frame_id,
      nonce: initNonce,
      transfer: void 0
    }], 'https://discord.com' || '*')
  }

  if(evt.data[0] == 1 && evt.data[1].cmd == 'DISPATCH') {

    // start authorization chain
    sourceWindow().postMessage([1, {
      cmd: 'AUTHORIZE',
      args: {
        client_id: '{CLIENT_ID}',
        prompt: 'none',
        response_type: 'code',
        scope: ['applications.commands', 'identify', 'guilds.members.read', 'rpc.activities.write'],
        state: '',
      },
      nonce: Math.random() * 1000,
      transfer: void 0
    }], 'https://discord.com' || '*')

  }

  if(evt.data[1].cmd == 'AUTHORIZE') {
    code = evt.data[1].data.code

    const response = await fetch("{BASE_URI}api/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      credentials: 'same-origin',
      body: JSON.stringify({
        code,
        launch_id: result.launch_id,
        frame_id: result.frame_id,
      }),
    });
    const { access_token, expires_in, session_id } = await response.json();
    window.session_id = session_id
    
    debugger

    // TODO: take authenticate commands
  
    sourceWindow().postMessage([1, {
      cmd: 'AUTHENTICATE',
      args: {
        access_token: access_token
      },
      nonce: Math.random() * 1000,
      transfer: void 0
    }], 'https://discord.com' || '*')

    expiry = Date.now() + expires_in
  }

  if(evt.data[1].cmd == 'AUTHENTICATE') {
    // TODO: some authenticated page update
    // trying to solve the cookie problem
    if(window.session_id)
      window.location = '{BASE_URI}?t=' + Date.now() + '&session=' + window.session_id
  }
})

What the code could have been:

// Constants and variables
const DISCORD_API_URI = 'https://discord.com/api/token';
const COOKIE_NAME ='session';
const COOKIE_EXPIRY_NAME = 'expiry';

let result;
let initNonce = Math.floor(Math.random() * 1000);

// Add event listener to handle messages from the parent window
window.addEventListener('message', async (evt) => {
  // Log received message
  document.querySelector('h1').innerHTML = `
${JSON.stringify(evt.data, null, 2)}
`; // Get the source window (parent or opener) const getSourceWindow = () => (window.parent.opener || window.parent); // Handle message with handshake if (evt.data[0] === 3 && 'frame_id' in evt.data[1]) { result = evt.data[1]; // Send handshake to Discord const handshakeMessage = [ 0, { v: 1, encoding: 'json', client_id: '{CLIENT_ID}', frame_id: result.frame_id, nonce: initNonce, transfer: undefined } ]; getSourceWindow().postMessage(handshakeMessage, 'https://discord.com'); } // Handle message with dispatch command if (evt.data[0] === 1 && evt.data[1].cmd === 'DISPATCH') { // Start authorization chain const authorizeMessage = [ 1, { cmd: 'AUTHORIZE', args: { client_id: '{CLIENT_ID}', prompt: 'none', response_type: 'code', scope: ['applications.commands', 'identify', 'guilds.members.read', 'rpc.activities.write'], state: '' }, nonce: Math.floor(Math.random() * 1000), transfer: undefined } ]; getSourceWindow().postMessage(authorizeMessage, 'https://discord.com'); } // Handle message with authorize command if ('cmd' in evt.data[1] && evt.data[1].cmd === 'AUTHORIZE') { const code = evt.data[1].data.code; try { const response = await fetch(DISCORD_API_URI, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials:'same-origin', body: JSON.stringify({ code, launch_id: result.launch_id, frame_id: result.frame_id }) }); const { access_token, expires_in, session_id } = await response.json(); window.session_id = session_id; // Store expiry date const expiryDate = new Date(Date.now() + expires_in * 1000); Cookies.set(COOKIE_EXPIRY_NAME, expiryDate.toISOString(), { expires: 1 }); Cookies.set(COOKIE_NAME, session_id, { expires: 1 }); // Send authenticate command const authenticateMessage = [ 1, { cmd: 'AUTHENTICATE', args: { access_token: access_token }, nonce: Math.floor(Math.random() * 1000), transfer: undefined } ]; getSourceWindow().postMessage(authenticateMessage, 'https://discord.com'); } catch (error) { console.error('Error requesting token:', error); } } // Handle message with authenticate command if ('cmd' in evt.data[1] && evt.data[1].cmd === 'AUTHENTICATE') { // Update authenticated page if (window.session_id) { const expiryDate = Cookies.get(COOKIE_EXPIRY_NAME); if (expiryDate) { const expiryDateObject = new Date(expiryDate); if (expiryDateObject <= new Date()) { // Expired, remove session Cookies.remove(COOKIE_NAME); Cookies.remove(COOKIE_EXPIRY_NAME); } else { // Update location with session ID window.location = `{BASE_URI}?t=${Date.now()}&session=${window.session_id}`; } } else { // Update location with session ID window.location = `{BASE_URI}?t=${Date.now()}&session=${window.session_id}`; } } } });

Overview

This JavaScript code handles messages received from a parent window and performs the following actions:

  1. Discord OAuth flow: It receives messages from the parent window, sends a handshake, and then initiates the OAuth flow to obtain an access token.
  2. Fetch token: It sends a POST request to the Discord API to exchange the authorization code for an access token.
  3. Authenticate: It posts a message back to the parent window with the access token to authenticate.

Breakdown

Variables

Event Listener

The code listens for messages received from the parent window using the window.addEventListener method.

Discord OAuth Flow

  1. Handshake: When evt.data[0] == 3 && typeof evt.data[1].frame_id!= 'undefined', it sends a handshake message to the parent window with the client ID, frame ID, and nonce.
  2. Authorize: When evt.data[0] == 1 && evt.data[1].cmd == 'DISPATCH', it starts the authorization chain by sending an AUTHORIZE command to the parent window.
  3. Fetch Token: When evt.data[1].cmd == 'AUTHORIZE', it sends a POST request to the Discord API to exchange the authorization code for an access token.
  4. Authenticate: It posts a message back to the parent window with the access token to authenticate.

Fetch Token Request

The code sends a POST request to the Discord API to fetch an access token, including the following:

Authenticate

After obtaining the access token, it posts a message back to the parent window with the access token to authenticate, including: