OAuth: Client doesn't exist

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    Successfully exchanging the authorization code for the access token
  2. What is the issue? Include screenshots / videos if possible!
    data: {
    error: ‘invalid_client’,
    error_description: ‘Client does not exist’
    }
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I double checked my code, I honestly don’t understand this error. I looked it up online & asked chatGPT for help and none were helpful.
app.js

const crypto = require(‘crypto’);
const axios = require(‘axios’)
const express = require(‘express’)
require(‘dotenv’).config()

const app = express()

app.use(express.static(‘public’))

let redirectURI = encodeURIComponent(“https://holocafe.nwygo.com/authorize”) // Note to self: Would redirect them to /authorize?code={code} | I can then access the code using params with express or smth ig
function base64URLEncode(str) {
return str.toString(‘base64’)
.replace(/+/g, ‘-’)
.replace(///g, ‘_’)
.replace(/=/g, ‘’);
}

console.log(“1”)

function sha256(buffer) {
return crypto.createHash(‘sha256’).update(buffer).digest(base64);
}

var code_verifier = base64URLEncode(crypto.randomBytes(32));

console.log("Generated code verifier: " + code_verifier);

async function generateCodeChallenge() {
return base64URLEncode(await sha256(code_verifier));
}

var code_challenge;

generateCodeChallenge().then(challenge => {
code_challenge = challenge;
console.log("Generated code challenge: " + code_challenge);
});

console.log(“2”);

console.log(“3”)
async function exchangeWithCode(code) {
console.log("Attempting to exchange code: " + code)
console.log("Using code verifier: " + code_verifier)
let clientsecret = process.env.clientSecret;
let clientid = process.env.clientID;
const response = await axios.post(
https://apis.roblox.com/oauth/v1/token’,
new URLSearchParams({
‘client_id’: clientid,
‘client_secret’: clientsecret,
‘grant_type’: ‘authorization_code’,
‘code’: code,
‘code_verifier’: code_verifier
})
);
console.log(response)
return response
}
console.log(“4”)
function exchangeWithRefreshToken(refreshToken) {
const data = new URLSearchParams();
data.append(‘grant_type’, “authorization_code”);
data.append(‘client_id’, process.env[“clientID”]);
data.append(‘client_secret’, process.env[“clientSecret”]);
data.append(‘refresh_token’, refreshToken)

axios.post('https://apis.roblox.com/oauth/v1/token', data, {
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
})
    .then(response => {
        return response
    })
    .catch(error => {
        console.error(error);
        return `Failed. Error: ${error}`
    });

}
console.log(“5”)
function getUserInfo(authCode) { // OAuth 2.0 Authentication | Documentation - Roblox Creator Hub
axios.get(‘https://apis.roblox.com/oauth/v1/userinfo’, {
headers: {
‘Authorization’: Bearer ${authCode}
}
})
.then(response => {
return response
})
.catch(error => {
console.error(error);
});
}
console.log(“6”)

console.log(“7”)

app.get(‘/authorize’, (req, res) => {
console.log(“Auth get request received”)
if (req.query.code) {
if (req.query.code) {
console.log("Received code: " + req.query.code)
// Successfully authorized. Run code to exchange for token
let exchangeRequest = exchangeWithCode(req.query.code)
console.log("Received the request: " + exchangeRequest)
let token = exchangeRequest.query.access_token
console.log("Access Token: " + token)
let refreshToken = exchangeRequest.query.refresh_token
console.log("Refresh token: " + refreshToken)

        let userInfo = getUserInfo(token)
        // Add code to store new refreshToken

        res.send({ userInfo })
    } else {
        console.log(`Failed to authorize. Error: ${req.error}. Description: ${req.error_description}. State: ${req.state}`)
        res.send("Failed")
    }
} else if (req.query.rf == "rf") {
    if (req.query.rf) {
        // Successfully authorized. Run code to exchange for token
        let request = exchangeWithRefreshToken(req.query.rf)
        let token = request.query.access_token
        let refreshToken = request.query.refresh_token

        // Add code to store new refreshToken


    } else {
        console.log(req)
        console.log(`Failed to authorize. Error: ${req.error}. Description: ${req.error_description}. State: ${req.state}`)
        res.send("Failed")
    }
} else {
    res.send("Invalid method")
}

})
console.log(“8”)
app.get(‘/codeverifier’, (req, res) => {
res.send(code_verifier)
})
app.get(‘/codechallenge’, (req, res) => {
res.send(code_challenge)
})
app.get(‘/logout’, (req, res) => {
// will do later – OAuth 2.0 Authentication | Documentation - Roblox Creator Hub
})

console.log(“9”)

app.listen(25024)

console.log(“10”)

script.js

var scopes = [“openid”, “profile”, “group:read”]; // Replace with all the scopes

async function GenerateOAuthURL() {
let code_verifier = await fetch(‘/codeverifier’).then(res => res.text());
let code_challenge = await fetch(‘/codechallenge’).then(res => res.text());

console.log("Code verifier (from client): " + code_verifier);
console.log("Code challenge (from client): " + code_challenge);

let redirectURI = encodeURIComponent("https://holocafe.nwygo.com/authorize") // Note to self: Would redirect them to /authorize?code={code} | I can then access the code using params with express or smth ig

var OAuthURL = "https://apis.roblox.com/oauth/v1/authorize" +
    "?client_id=2969482479946332042" +
    "&code_challenge=" + code_challenge +
    "&code_challenge_method=S256" +
    "&redirect_uri=" + redirectURI +
    "&scope=" + scopes.join("%20") +
    "&response_type=code" +
    "&state=abc123";

console.log("OAuthURL:", OAuthURL);

let authButton = document.getElementById('authButton');
authButton.href = OAuthURL;

}

GenerateOAuthURL();

.env

clientID=“**”,
clientSecret=“RBX-****”

Explorer view:
image

Reason to help me with my problem:

  • You get marked as solution if it fixes my problem :sunglasses:
  • Sense of accomplishments
  • Being helpful to community

Could you post your code formatted better?

Roblox offers a sample code which works perfectly fine, check it out, maybe it’ll help ya.

const crypto = require('crypto');
const axios = require('axios')
const express = require('express')
require('dotenv').config()

const app = express()

app.use(express.static('public'))

let redirectURI = encodeURIComponent("https://holocafe.nwygo.com/authorize") // Note to self: Would redirect them to /authorize?code={code} | I can then access the code using params with express or smth ig
function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

console.log("1")

function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest(`base64`);
}

var code_verifier = base64URLEncode(crypto.randomBytes(32));

console.log("Generated code verifier: " + code_verifier);

async function generateCodeChallenge() {
    return base64URLEncode(await sha256(code_verifier));
}

var code_challenge;

generateCodeChallenge().then(challenge => {
    code_challenge = challenge;
    console.log("Generated code challenge: " + code_challenge);
});

console.log("2");

console.log("3")
async function exchangeWithCode(code) {
    console.log("Attempting to exchange code: " + code)
    console.log("Using code verifier: " + code_verifier)
    let clientsecret = process.env.clientSecret;
    let clientid = process.env.clientID;
    const response = await axios.post(
        'https://apis.roblox.com/oauth/v1/token',
        new URLSearchParams({
            'client_id': clientid,
            'client_secret': clientsecret,
            'grant_type': 'authorization_code',
            'code': code,
            'code_verifier': code_verifier
        })
    );
    console.log(response)
    return response
}
console.log("4")
function exchangeWithRefreshToken(refreshToken) {
    const data = new URLSearchParams();
    data.append('grant_type', "authorization_code");
    data.append('client_id', process.env["clientID"]);
    data.append('client_secret', process.env["clientSecret"]);
    data.append('refresh_token', refreshToken)

    axios.post('https://apis.roblox.com/oauth/v1/token', data, {
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    })
        .then(response => {
            return response
        })
        .catch(error => {
            console.error(error);
            return `Failed. Error: ${error}`
        });
}
console.log("5")
function getUserInfo(authCode) { // https://create.roblox.com/docs/cloud/reference/oauth2#get-v1userinfo
    axios.get('https://apis.roblox.com/oauth/v1/userinfo', {
        headers: {
            'Authorization': `Bearer ${authCode}`
        }
    })
        .then(response => {
            return response
        })
        .catch(error => {
            console.error(error);
        });
}
console.log("6")

console.log("7")

app.get('/authorize', (req, res) => {
    console.log("Auth get request received")
    if (req.query.code) {
        if (req.query.code) {
            console.log("Received code: " + req.query.code)
            // Successfully authorized. Run code to exchange for token
            let exchangeRequest = exchangeWithCode(req.query.code)
            console.log("Received the request: " + exchangeRequest)
            let token = exchangeRequest.query.access_token
            console.log("Access Token: " + token)
            let refreshToken = exchangeRequest.query.refresh_token
            console.log("Refresh token: " + refreshToken)

            let userInfo = getUserInfo(token)
            // Add code to store new refreshToken

            res.send({ userInfo })
        } else {
            console.log(`Failed to authorize. Error: ${req.error}. Description: ${req.error_description}. State: ${req.state}`)
            res.send("Failed")
        }
    } else if (req.query.rf == "rf") {
        if (req.query.rf) {
            // Successfully authorized. Run code to exchange for token
            let request = exchangeWithRefreshToken(req.query.rf)
            let token = request.query.access_token
            let refreshToken = request.query.refresh_token

            // Add code to store new refreshToken


        } else {
            console.log(req)
            console.log(`Failed to authorize. Error: ${req.error}. Description: ${req.error_description}. State: ${req.state}`)
            res.send("Failed")
        }
    } else {
        res.send("Invalid method")
    }
})
console.log("8")
app.get('/codeverifier', (req, res) => {
    res.send(code_verifier)
})
app.get('/codechallenge', (req, res) => {
    res.send(code_challenge)
})
app.get('/logout', (req, res) => {
    // will do later -- https://create.roblox.com/docs/cloud/reference/oauth2#post-v1tokenrevoke
})

console.log("9")

app.listen(25024)

console.log("10")

I have tried the sample code before and it didn’t work (at least the way I would be using it).

Are you sure the authorization token is correct?

Yes, I am sure that the authorization code is correct because I can see it in the URL and it doesn’t say undefined or anything like that.

This still isn’t solved, if anyone has any ideas on how to fix it, it would be greatly appreciated.