Even after setting auth:true in api end point in main.wasp api end point is not secure.

I can still call my api simply from http://localhost:3000/api/custom-api-endpoint-with-parameters and it shows api response with data. How to solve this and make it secure?
30 Replies
kapa.ai
kapa.ai2mo ago
Hi @Killshot. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To secure your API endpoint in Wasp, you need to ensure that the auth field is set to true in your API declaration in the main.wasp file. This will enable authentication and provide a context.user object. If you do not wish to attempt to parse the JWT in the Authorization Header, you should set this to false. Here is an example of how to set it:
api fooBar {
fn: import { fooBar } from "@src/apis",
httpRoute: (GET, "/foo/bar"),
entities: [Task],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@src/apis"
}
api fooBar {
fn: import { fooBar } from "@src/apis",
httpRoute: (GET, "/foo/bar"),
entities: [Task],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@src/apis"
}
In the above example, auth: true means that the API endpoint is secured and requires authentication. However, setting auth: true only means that the endpoint expects an authenticated user. If you want to enforce that the endpoint can't be accessed without authentication, you need to check the context.user in your API's NodeJS implementation. If context.user is not present, it means the request is not authenticated, and you should return an error. Here is an example of how to do it:
export const fooBar = (req, res, context) => {
if (!context.user) {
throw new HttpError(401) // Unauthenticated
}
// Rest of your code
};
export const fooBar = (req, res, context) => {
if (!context.user) {
throw new HttpError(401) // Unauthenticated
}
// Rest of your code
};
In the above example, if context.user is not present, an HTTP 401 error is thrown, indicating that the request is not authenticated. Please refer to the following sources for more information: - API Reference (https://wasp-lang.dev/docs/advanced/apis#api-reference) - Defining the API's NodeJS Implementation (https://wasp-lang.dev/docs/advanced/apis#defining-the-apis-nodejs-implementation) - Updating Operations to Check Authentication (https://wasp-lang.dev/docs/tutorial/auth#updating-operations-to-check-authentication) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Killshot, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Vinny (@Wasp)
Vinny (@Wasp)2mo ago
can you share the relevant code from your API as well as its definition in your main wasp config file?
martinsos
martinsos2mo ago
@Killshot check out the docs here: https://wasp-lang.dev/docs/advanced/apis#api-reference -> auth: true does not mean it will not allow unauthenticated users, but that it will check if there is an authenticated user and if so, provide it for you in context.user. You are then to implement the checkyourself -> you can do if (!context.user) or whatever you want to check. auth: true "just" detects logged in user if there is such and provides it to you so you can implement your custom logic.
Custom HTTP API Endpoints | Wasp
In Wasp, the default client-server interaction mechanism is through Operations. However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an api. Best of all, they should look and feel very familiar.
martinsos
martinsos2mo ago
Ha, actually Kapa already have a good answer, I missed it! Yeah, Kappa already said it correctly. But @Killshot , what is true is that this is confusing. auth: true does sound a bit too much like auth is required. We have a GH issue here to give it some better name: https://github.com/wasp-lang/wasp/issues/1133, and I will also link it to this discord convo.
Killshot
KillshotOP2mo ago
Is this syntax correct or am i messing somethng up?
import axios from 'axios';
import { HttpError } from 'wasp/server';

export const getRandomDogImage = async (args, context) => {
// Check if the user is authenticated
if (!context.user) {
throw new HttpError(401, 'User not authenticated');
}

try {

const response = await axios.get('https://dog.ceo/api/breeds/image/random');


if (response.status === 200 && response.data.message) {
return { imageUrl: response.data.message };
} else {
throw new Error('Invalid response from Dog API');
}
} catch (error) {
console.error('Error fetching dog image:', error);
throw new HttpError(500, 'Failed to fetch dog image');
}
};
import axios from 'axios';
import { HttpError } from 'wasp/server';

export const getRandomDogImage = async (args, context) => {
// Check if the user is authenticated
if (!context.user) {
throw new HttpError(401, 'User not authenticated');
}

try {

const response = await axios.get('https://dog.ceo/api/breeds/image/random');


if (response.status === 200 && response.data.message) {
return { imageUrl: response.data.message };
} else {
throw new Error('Invalid response from Dog API');
}
} catch (error) {
console.error('Error fetching dog image:', error);
throw new HttpError(500, 'Failed to fetch dog image');
}
};
This is my main.wasp configuration for same test API --
api randomDogImage {
fn: import { getRandomDogImage } from "@src/appapis/apis.js",
httpRoute: (GET, "/api/random-dog"),
auth: true,
}
api randomDogImage {
fn: import { getRandomDogImage } from "@src/appapis/apis.js",
httpRoute: (GET, "/api/random-dog"),
auth: true,
}
@martinsos
martinsos
martinsos2mo ago
@Killshot this looks good to me, at first glance! Why are you asking though, are you referring to your usage of auth: true and then if (!context.user)? If so, that part makes sense to me. Now only authenticated users should be able to run that api. Or do you have some issue still, is that why you are asking?
Killshot
KillshotOP2mo ago
Yeah, so even after making sure i have auth:true in main.wasp for this relevant part and context.user check in api code, i am now consistently getting 401 error even though i am logged in via Google Oauth, i did logout and log in again and still same issue. am i missing something in cookies or session settings?
martinsos
martinsos2mo ago
@Killshot ooooh wait, I have an idea -> how are you doing those API requests? Are you doing it as specified here https://wasp-lang.dev/docs/advanced/apis#using-the-api-from-the-client ? By importing api from wasp/client/api? Because this api is provided by wasp and will therefore do these calls correctly, with the authentication set correctly. If you do it on your own, with axios directly or fetch or something like that, you will not have auth credentials set during that call.
Killshot
KillshotOP2mo ago
Ohh that solves it and even makes sense i guess. I was doing it directly via axios
martinsos
martinsos2mo ago
Ahh sorry about that @Killshot . Is there a place in docs we could have made this clearer maybe? I understand that this is easy mistake to do.
Killshot
KillshotOP2mo ago
I did use search feature and might have even went through this without realizing it. My bad @martinsos
martinsos
martinsos2mo ago
You are not the first one to stubmle on it though. I created an issue for it here now https://github.com/wasp-lang/wasp/issues/2350 , we really should figure out a way to make it harder for people to make this mistake. It is just too easy to just go with axios or fetch and forget about this. I wrote down some ideas in that issue.
Killshot
KillshotOP2mo ago
Appreciate it boss, I guess a disclaimer of some kind in our own opensaas docs would have solved it for me in seconds. Not much just a description of how one would need custom API endpoints and then linking them to this https://wasp-lang.dev/docs/advanced/apis#using-the-api-from-the-client wasp generic docs regarding calling api from client side. I did check this out https://docs.opensaas.sh/guides/authorization/#server-side-authorization but it didn't solve it completely.
Custom HTTP API Endpoints | Wasp
In Wasp, the default client-server interaction mechanism is through Operations. However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an api. Best of all, they should look and feel very familiar.
OpenSaaS.sh
Authorization
Open SaaS is a free, open-source, full-stack SaaS starter kit for React + NodeJS.
Killshot
KillshotOP2mo ago
@martinsos Hey, This worked as expected in the local environment, but it's giving cors error after deployment. anything off the top of your head why it could be happening?
miho
miho2mo ago
What are your client and server URLs? What kind of errors are you seeing?
Killshot
KillshotOP2mo ago
You're gonna like this, It was the referer check in the Nginx configuration, had to setup up properly to make api endpoints secure. Thinking of going to caddy more and more
miho
miho2mo ago
Caddy is super simple, powerful and I haven't looked back since I moved away from Nginx 🙂 If you do decide to try them - let me know if I can help with it.
Killshot
KillshotOP2mo ago
Hey i did migrate to caddy, but can't get it to work. you mind taking a look?
miho
miho2mo ago
Gist
Deploy Wasp to a VPS (reverse proxy + Docker)
Deploy Wasp to a VPS (reverse proxy + Docker). GitHub Gist: instantly share code, notes, and snippets.
Killshot
KillshotOP2mo ago
{
# Use Cloudflare DNS challenge for ACME
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}

mysite.com, www.mysite.com {
root * /killshot/webdevelopment/mysite/client
encode gzip
try_files {path} /index.html
file_server
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}

api.mysite.com {
reverse_proxy localhost:3001
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}

bot.mysite.com {
reverse_proxy localhost:3000
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}
{
# Use Cloudflare DNS challenge for ACME
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}

mysite.com, www.mysite.com {
root * /killshot/webdevelopment/mysite/client
encode gzip
try_files {path} /index.html
file_server
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}

api.mysite.com {
reverse_proxy localhost:3001
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}

bot.mysite.com {
reverse_proxy localhost:3000
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}
yeah definitely, also got it to partially work with nginx but then got tired of the few cors issue i was getitng. is it mandatory to link to origin certificates for cloudflare?
miho
miho2mo ago
Everything seems fine to me 🤷‍♂️ do you get any errors? I've never used Cloudflare like this with Caddy, so I can't really say if that bit is correct. Did you try Googling errors you see? Bonus I'd create a redirect from www to non-www, not serve the client - unless you set up CORS to handle both 😄 systemctl -l status caddy to see Caddy logs
Killshot
KillshotOP2mo ago
yeah log command shows it's active and no issues shown
MEE6
MEE62mo ago
Wohooo @Killshot, you just became a Waspeteer level 7!
miho
miho2mo ago
You said this:
but can't get it to work.
but what does that mean? Your client is not loading? Your server is not loading? Are you seeing errors in the browser console? Are you seeing errors in the server logs?
Killshot
KillshotOP2mo ago
yeah nothing is shown on mysite.com nor api.mysite.com
miho
miho2mo ago
I'd start from scratch and try to serve only the client and see what happens. Just using the built in TLS certs and not Cloudflare. Then, I'd add Cloudflare and see if it still works. Of course, you got to wait for DNS to propagate and stuff like that. Then I'd try adding the server and the bot sections and see if it still works. You got to reduce the area where the error can happen and then start checking every little bit.
Killshot
KillshotOP2mo ago
Sure let me do that. will keep the thread updated.
Vinny (@Wasp)
Vinny (@Wasp)4w ago
Just following up on this. Were you able to resolve your issue?
Killshot
KillshotOP4w ago
Not yet. My api endpoints works as expected in local environment. But not in production with cloudflare and caddy.
Vinny (@Wasp)
Vinny (@Wasp)4w ago
@Killshot Did you try the process @miho suggested above?
Want results from more Discord servers?
Add your server