OAuth 2 Bad Request when trying get the Token

I’m trying to make a simple API with OAuth 2 in Express.js

Everything work fine but when trying to get the Token with the code I got It give me “Bad Request”

I tried adding Authorization: Basic Base64 encoded(<client_id>:<client_secret>) Like it said here like this but id didn’t work


  const tokenReqParams = new URLSearchParams({
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    code: code,
    grant_type: 'authorization_code',
  });

  const tokenRes = await fetch("https://apis.roblox.com/oauth/v1/token", {
    method: "POST",
    headers: {
      Authorization: "Basic " + Buffer.from(CLIENT_ID + ":" + CLIENT_SECRET).toString("base64"),
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: tokenReqParams,
  });

FULL CODE:

const express = require("express");

const router = express.Router();

// GET: localhost:3001/auth/signin
// GET: localhost:3001/auth/redirect

router.get("/signin", (req, res) => {
  res.redirect(
    `https://apis.roblox.com/oauth/v1/authorize?client_id=6775085468035985992&redirect_uri=http://localhost:3001/auth/redirect&scope=openid%20profile%20group:read&response_type=code`
  );
});

router.get("/redirect", async (req, res) => {
  const CLIENT_ID = 6775085468035985992;
  const CLIENT_SECRET = "RBX-";

  const { code } = req.query;

  if (!code) {
    return res.status(400).json({
      error: 'A "code" query parameter must be present in the URL.',
    });
  }

  const tokenReqParams = new URLSearchParams({
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    code: code,
    grant_type: 'authorization_code',
  });

  const tokenRes = await fetch("https://apis.roblox.com/oauth/v1/token", {
    method: "POST",
    headers: {
      Authorization: "Basic " + Buffer.from(CLIENT_ID + ":" + CLIENT_SECRET).toString("base64"),
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: tokenReqParams,
  });

  if (!tokenRes.ok) {
    console.log("error", tokenRes);
    res.send("error");
    return;
  }

  const oauthResJson = await tokenRes.json();

  const userRes = await fetch(`https://apis.roblox.com/oauth/v1/userinfo`, {
    method: "GET",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      Authorization: `Bearer ${oauthResJson.access_token}`,
    },
  });

  const resourcesRes = await fetch(
    `https://apis.roblox.com/oauth/v1/userinfo`,
    {
      method: "GET",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Authorization: `Bearer ${oauthResJson.access_token}`,
      },
    }
  );

  if (!userRes.ok & !resourcesRes.ok) {
    return res.send("error");
  }

  const userResJson = await userRes.json();
  const resourcesResJson = await resourcesRes.json();

  console.log(userResJson, resourcesResJson);
  res.send(
    "<h1>Authenticated</h1><p>User info:</p><pre>" +
      JSON.stringify(userResJson, null, 2) +
      "</pre><p>Resources info:</p><pre>" +
      JSON.stringify(resourcesResJson, null, 2) +
      "</pre>"
  );
});

module.exports = router;