Setting up oauth API

my dashboard is hosted on https://cardinal.oreotm.xyz and my backend is hosted on a vps on [ipaddress] Backend Setup:
auth: {
id: BotClientID,
secret: envParseString('OAUTH_SECRET'),
cookie: 'CARDINAL_AUTH', //envParseString('OAUTH_COOKIE'),
redirect: 'https://cardinal.oreotm.xyz/oauth/discord/callback', // envParseString('OAUTH_REDIRECT_URI')
scopes: [OAuth2Scopes.Identify, OAuth2Scopes.Guilds],
transformers: [transformOauthGuildsAndUser],
domainOverwrite: '.oreotm.xyz' //envParseString('OAUTH_DOMAIN_OVERWRITE')
},
prefix: '/', //envParseString('API_PREFIX'),
origin: 'https://cardinal.oreotm.xyz', //envParseString('API_ORIGIN'),
listenOptions: {
port: 4000
}
auth: {
id: BotClientID,
secret: envParseString('OAUTH_SECRET'),
cookie: 'CARDINAL_AUTH', //envParseString('OAUTH_COOKIE'),
redirect: 'https://cardinal.oreotm.xyz/oauth/discord/callback', // envParseString('OAUTH_REDIRECT_URI')
scopes: [OAuth2Scopes.Identify, OAuth2Scopes.Guilds],
transformers: [transformOauthGuildsAndUser],
domainOverwrite: '.oreotm.xyz' //envParseString('OAUTH_DOMAIN_OVERWRITE')
},
prefix: '/', //envParseString('API_PREFIX'),
origin: 'https://cardinal.oreotm.xyz', //envParseString('API_ORIGIN'),
listenOptions: {
port: 4000
}
Frontend Code:
const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: REDIRECT_URI
})
});
const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: REDIRECT_URI
})
});
When i host the frontend on my local machine the login data is returned, but when i host the site on the domain it returns 'Bad request'. How do i properly set the api up?
Solution:
something like http://207.xxx.xxx.xxx:4000 could it be because im mixing http and https while using credentials: 'include'...
Jump to solution
56 Replies
Favna
Favna7mo ago
have you checkedo out https://www.sapphirejs.dev/docs/Guide/plugins/API/using-oauth2-backend-route and the accompying frontend page? You also seem to have copied code from @Skyra seeing as you also have the transformOauthGuildsAndUsers, keep in mind that Skyra is still using @sapphire/framework v2. Furthermore, that bad request ultimately gets returned from your own host after all so you should be able to view a reason why, i.e. by using debugging breakpoints.
Sapphire Framework
Using the built in OAUTH2 route (backend) | Sapphire
If you are using localhost as your test environment, make sure you use http//localhost in
Oreo ™
Oreo ™7mo ago
yup i first copied that when i was only running it on localhost and everything worked fine but the cookie didnt set, and later i tried to host it on the domain and i got the bad request error. So i decided to search for solutions in this server and i saw someone having the same problem so i copied their config, but it still didnt work. Nothing gets logged on the backend. I remember it used to log stuff like invalid_grant and invalid_redirect_uri but now it doesnt log the error at all. The most weirdest thing is that it returns the login data when in on localhost but not when im on cardinal.oreotm.xyz okay so i made some changes Now i get this error in the backend
{
error: 'invalid_grant',
error_description: 'Invalid "redirect_uri" in request.'
}
{
error: 'invalid_grant',
error_description: 'Invalid "redirect_uri" in request.'
}
when i make the following request from the front end
const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: 'http://localhost:5173/oauth/discord/callback'
})
});
const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: 'http://localhost:5173/oauth/discord/callback'
})
});
Oreo ™
Oreo ™7mo ago
but when i make the same request with the redirectUri set to https://cardinal.oreotm.xyz/oauth/discord/callback on the front end it doesnt log anything in the console and login data is returned as bad request
No description
Oreo ™
Oreo ™7mo ago
alright so i looked at https://discord.com/channels/737141877803057244/1111812366296948736/1111812366296948736 and the only thing i can see different is that his api is hosted on a subdomain of his bots dashboard domain, will that be an issue in my case? since im just making an api request to the IP:PORT of the vps im using my bot on, i dont really now how to make api.oreotm.xyz be pointed to my bot so yeah Ok i have an update Im using this to make the request
const body = JSON.stringify({
code: code,
redirectUri: REDIRECT_URI
});

const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: body
});
const body = JSON.stringify({
code: code,
redirectUri: REDIRECT_URI
});

const response = await fetch(`${BASE_CARDINAL_API_URL}/oauth/callback`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: body
});
on both localhost and the actual website hosted on vercel and i can assure that the redirect uri is correct on prod: https://oreotm.xyz/oauth/discord/callback on dev: http://localhost:5173/oauth/discord/callback But when i click the login button on the vercel website i get
{ error: 'Bad Request' }
{ error: 'Bad Request' }
But on localhost i get the full login data with the transformed guilds and everything And on the backend (bot) i have hardcoded the api config as so
api: {
auth: {
id: BotClientID,
secret: envParseString('OAUTH_SECRET'),
cookie: 'CARDINAL_AUTH', //envParseString('OAUTH_COOKIE'),
// redirect: 'https://oreotm.xyz/oauth/discord/callback', // envParseString('OAUTH_REDIRECT_URI')
scopes: [OAuth2Scopes.Identify, OAuth2Scopes.Guilds],
transformers: [transformOauthGuildsAndUser]
// domainOverwrite: '.oreotm.xyz' //envParseString('OAUTH_DOMAIN_OVERWRITE')
},
prefix: '/', //envParseString('API_PREFIX'),
origin: '*', //envParseString('API_ORIGIN'),
listenOptions: {
port: 4000
}
}
api: {
auth: {
id: BotClientID,
secret: envParseString('OAUTH_SECRET'),
cookie: 'CARDINAL_AUTH', //envParseString('OAUTH_COOKIE'),
// redirect: 'https://oreotm.xyz/oauth/discord/callback', // envParseString('OAUTH_REDIRECT_URI')
scopes: [OAuth2Scopes.Identify, OAuth2Scopes.Guilds],
transformers: [transformOauthGuildsAndUser]
// domainOverwrite: '.oreotm.xyz' //envParseString('OAUTH_DOMAIN_OVERWRITE')
},
prefix: '/', //envParseString('API_PREFIX'),
origin: '*', //envParseString('API_ORIGIN'),
listenOptions: {
port: 4000
}
}
And i have changed the production website url to be https://oreotm.xyz since i thought the subdomain might be messing up the oauth So why is it that on localhost it returns the logindata but not on the actual production site? You can ignore the previous messages and start reading from here
Favna
Favna7mo ago
Did you setup the redirect URL on the discord bot dashboard?
Favna
Favna7mo ago
Discord Developer Portal
Discord Developer Portal — API Docs for Bots and Developers
Integrate your service with Discord — whether it's a bot or a game or whatever your wildest imagination can come up with.
Favna
Favna7mo ago
like this
No description
Favna
Favna7mo ago
also if you're using the built in oauth callback endpoint from the api plugin then it's /oauth/callback, not /oauth/discord/callback
Oreo ™
Oreo ™7mo ago
yup even on the frontend?
Oreo ™
Oreo ™7mo ago
because im calling the built in oauth api correctly
No description
Oreo ™
Oreo ™7mo ago
unless u mean on the redirectUri in the body that it should also be /oauth/callback anyhow i changed the frontend oauth link from /oauth/discord/callback to /oauth/callback
Oreo ™
Oreo ™7mo ago
No description
Oreo ™
Oreo ™7mo ago
No description
Favna
Favna7mo ago
this yes
Oreo ™
Oreo ™7mo ago
okay i did that, and i made sure it worked by console logging the redirect uri here
No description
No description
Oreo ™
Oreo ™7mo ago
still i get this error { error: 'Bad Request' } i checked the sapphire/plugin-api src code and it returns Bad Request when the code isnt a string, i think but i checked the code and its there
Oreo ™
Oreo ™7mo ago
No description
Favna
Favna7mo ago
I have no idea then. You could leverage yarn patches / patch-package (for npm/pnpm) to add console logging.. or use VSCode Remote Server to make it so you can set a breakpoint on your prod run. problem with this kinda stuff is that it's so heavily environment dependant that I cannot do much for you either
Oreo ™
Oreo ™7mo ago
maybe the bots config?
No description
Oreo ™
Oreo ™7mo ago
if not ill go back to the oauth system i had made before, i just wanted to use sapphires one bc of the LoginData object
Favna
Favna7mo ago
what kind of frontend do you use? next? react? vue?
Oreo ™
Oreo ™7mo ago
svelte is that the problem? but i saw someone else use svelte with sapphires/plugin-api too
Favna
Favna7mo ago
ah I dont have experienc with that but if you say the code is definitely being sent then you're probably right nah it shouldnt be you logged the body after stringifying it and before sending it?
Oreo ™
Oreo ™7mo ago
yup
Oreo ™
Oreo ™7mo ago
localhost:
No description
Oreo ™
Oreo ™7mo ago
idk why localhost works just fine even with the current hard coded api config here (just in case it might help)
Favna
Favna7mo ago
for @Skyra the config is as follows Frontend Step 1 - User clicks the button to login. That button has the URL: https://discord.com/oauth2/authorize?redirect_uri=https%3A%2F%2Fskyra.pw%2Foauth%2Fcallback&response_type=code&scope=identify+guilds&client_id=266624760782258186 - This URL gets build up here: https://github.com/skyra-project/skyra.pw/blob/main/src/utils/constants.ts#L9-L14 Step 2 - https://github.com/skyra-project/skyra.pw/blob/main/src/pages/oauth/callback.tsx - The user gets sent back to this page by Discord after they authorise. We receive the code from Discord and then send the request to the api plugin route. We provide the SAME url as the current page as the redirect uri before so React doesn't navigate us away thus losing our state, instead we just end up receiving the data and processing it. - redirectUri: ${BASE_WEB_URL}/oauth/callback ==> redirectUri: https://skyra.pw/oauth/callback (this is a FRONTEND route! Not a backend one which would be https://api.skyra.pw) - clientId is @Skyra 's client id. A variable here because we use dev bots for dev. You could hard code it to your bot's client id. - code as you know, parsed from the querystring. Backend - https://github.com/skyra-project/skyra/blob/main/src/config.ts#L46-L69 - Also see image below. - The domain overwrite is because we have the backend on api.skyra.pw and the default for the domain would be skyra.pw which then has the cookie not match. If you host your backend on for example https://oreotm.xyz/api through routing then you don't need the domain overwrite
No description
Favna
Favna7mo ago
hope that helps
Oreo ™
Oreo ™7mo ago
ok so since im hosting the api on a vps that doesnt actually have a domain but instead i just connect to it using its ip i dont need domainOverwrite and what does API_ORIGIN actually do? and my setup is similar to skyras setup
Favna
Favna7mo ago
so you're saying that BASE_CARDINAL_API_URL is an IP address?
Oreo ™
Oreo ™7mo ago
yeah.. with the port that the api is configed to listen to
Favna
Favna7mo ago
as for API_ORIGIN, that sets the Access-Control-Allow-Origin which defaults to *
Solution
Oreo ™
Oreo ™7mo ago
something like http://207.xxx.xxx.xxx:4000 could it be because im mixing http and https while using credentials: 'include'
Favna
Favna7mo ago
uh yeah you should definitely only use https
Favna
Favna7mo ago
You can use cloudflare are your dns even when using Vercel (that's literally what https://sapphirejs.dev does too) and then you can get free SSL
Sapphire Framework
Home | Sapphire
Sapphire is a next-gen Discord bot framework for developers of all skill levels to make the best JavaScript/TypeScript based bots possible.
Favna
Favna7mo ago
as well as a free subdomain that you just point to a different IP address different A records
Oreo ™
Oreo ™7mo ago
yeah the domain is using cloudflare dns but i couldnt get the api.oreotm.xyz to be pointed to this IP bc of ports and stuff wait ill try something
Favna
Favna7mo ago
api.oreotm.xyz point it to 207.xxx.xxx.xxx, dont add a port on cloudflare.
Oreo ™
Oreo ™7mo ago
and it will get requests from 207.xxx.xxx.xxx:4000 ??
Favna
Favna7mo ago
I mean you'll have to use nginx on the VPS to expose the localhost and port
Oreo ™
Oreo ™7mo ago
yeah ill try that
Favna
Favna7mo ago
on nginx you configure localhost:4000 to go to api.oreotm.xyz and then on CF you configure the same to go to the IP address btw just my 2 cents but if you're using CF anyway then why use Vercel? I mean if you want GH integration you can use CF pages
Oreo ™
Oreo ™7mo ago
idk how else to host my sveltekit site im new to this frontend stuff
Favna
Favna7mo ago
Deploy a Svelte site · Cloudflare Pages docs
Svelte is an increasingly popular, open-source framework for building user interfaces and web applications. Unlike most frameworks, Svelte is …
Favna
Favna7mo ago
I've never used Svelte/Sveltekit before mind you so I can't be much help other than giving that doc site but I know it should be possible FWIW this wouldn't necessarily alleviate issues with all the OAUTH stuff Just that it's a bit wacky to use 2 platforms when 1 suffices
Oreo ™
Oreo ™7mo ago
true ill look into that thanks for ur help
KB
KB7mo ago
@Oreo ™ Here's a SvelteKit implementation you can check if it helps, though I haven't touched it in a while: https://github.com/KBot-discord/KBot/blob/main/apps/web/src/routes/(api)/oauth/discord/callback/%2Bserver.ts
KB
KB7mo ago
Oh I didn't notice lol
Oreo ™
Oreo ™7mo ago
Also i know this is not related to sapphire but are you able to link me a resource to link api.oreotm.xyz to 207.xxx.xxx.xxx:4000 with nginx? i searched around and found like 3 videos telling me to do 3 different things. One tells me to create a file called api.oreotm.xyz in conf.d/ and another tell me to edit a prexisting file, and none of them seems to work. right now im using cloudflare tunnels i mean it works
Oreo ™
Oreo ™7mo ago
No description
Oreo ™
Oreo ™7mo ago
¯\_(ツ)_/¯
Favna
Favna7mo ago
this goes in sites-available and then you symlink it to sites-enabled
upstream ALIAS_HERE {
server 127.0.0.1:THE_LOCAL_PORT;
keepalive 8;
}

server {
listen 80;
listen 443 ssl http2;

server_name api.oreotm.xyz;

access_log /var/log/nginx/api.oreotm.xyz;

ssl_certificate /path/to/cloudflare/perms/file.pem;
ssl_certificate_key /path/to/cloudflare/perms/file.key;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://ALIAS_HERE/;
proxy_redirect off;
}
}
upstream ALIAS_HERE {
server 127.0.0.1:THE_LOCAL_PORT;
keepalive 8;
}

server {
listen 80;
listen 443 ssl http2;

server_name api.oreotm.xyz;

access_log /var/log/nginx/api.oreotm.xyz;

ssl_certificate /path/to/cloudflare/perms/file.pem;
ssl_certificate_key /path/to/cloudflare/perms/file.key;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://ALIAS_HERE/;
proxy_redirect off;
}
}
Oreo ™
Oreo ™7mo ago
thanks so much
Favna
Favna7mo ago
so ultimately it was just exposing it through a subdomain instead of ip?
Oreo ™
Oreo ™7mo ago
yup