Minimal working API with jwt example?
Hey, I'm liking the plug and play aspects of wasp. It would seem to me that you could easily add a bit more API support for beginners. (Parsing a basic jwt that we could later and more fields to + explaining how to create a new key when going to production) Any plans for this? In the meantime is there an API POC repo I can see something minimal doing this with wasp? I noticed you have all the client libraries, so I assume you handle caching the token, but it seems strange that you would do the front end work without the backend as well. Maybe I'm missing something. Or is there a complication I don't yet know of I'm doing this? Are there any api's in the saas-starter-template that I can look at? It searched for jwt and didn't see anything. My goal is to build something that can easily be used for my mobile backend later.
30 Replies
Hi @Captain Incredible. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Wasp does not currently provide a minimal, official example or POC repository specifically focused on a JWT-based API out of the box. While Wasp handles authentication and JWTs internally for its built-in auth system, there isn’t a dedicated, minimal API example in the starter templates or the saas-starter-template that demonstrates custom JWT parsing or issuing for general API use, especially for mobile backends.
However, there are community discussions and code snippets showing how you can add a custom API endpoint for generating JWTs. For example, you can define a custom API in your
Wasp reads the JWT secret from an environment variable (e.g.,
Wasp’s current auth system is designed for its web client, and exposing a general-purpose API for mobile clients is not yet officially supported. There are community experiments and discussions about using Wasp as a backend for mobile apps, but it requires manual setup and is not as plug-and-play as the web client Have Wasp support producing mobile (smartphone) client app, Support for multiple clients, How can I authenticate a user from a mobile app. Summary:
- No official minimal JWT API example repo exists yet. - You can add a custom JWT API endpoint as shown above. - JWT secret should be set via environment variable. - Wasp’s mobile backend support is experimental and community-driven for now. If you need a ready-to-use example, the above pattern is the closest available, and you can adapt it for your needs. If you want to see this as an official template or feature, consider upvoting or commenting on the related GitHub issues. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
main.wasp file and implement the JWT logic in a server file. Here’s a minimal pattern based on a real-world discussion:
main.wasp
generateJwt.ts
This approach is discussed in detail in a Discord support thread, including troubleshooting tips if your endpoint returns 404 (make sure to restart the Wasp server after changes) Best Practices for Implementing Auth System in Chrome Extension Connected to OpenSaaS.
On JWT Secret Management:Wasp reads the JWT secret from an environment variable (e.g.,
JWT_SECRET or JWT_SECRET_KEY). There are ongoing discussions about making this process easier, such as generating the secret automatically during deployment, but currently, you need to set it yourself in your environment configuration JWT secret must not be hardcoded in the back-end code, Randomly generate JWT secret at appropriate times?.
On Mobile Backend Readiness:Wasp’s current auth system is designed for its web client, and exposing a general-purpose API for mobile clients is not yet officially supported. There are community experiments and discussions about using Wasp as a backend for mobile apps, but it requires manual setup and is not as plug-and-play as the web client Have Wasp support producing mobile (smartphone) client app, Support for multiple clients, How can I authenticate a user from a mobile app. Summary:
- No official minimal JWT API example repo exists yet. - You can add a custom JWT API endpoint as shown above. - JWT secret should be set via environment variable. - Wasp’s mobile backend support is experimental and community-driven for now. If you need a ready-to-use example, the above pattern is the closest available, and you can adapt it for your needs. If you want to see this as an official template or feature, consider upvoting or commenting on the related GitHub issues. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
We made an example Expo app (but the Wasp side is the same for any kind of app later): https://github.com/wasp-lang/wasp-expo-app
We want ot improve this part though! You can follow the Mobile support item in our 1.0 roadmap and get notified when there are any updates https://github.com/wasp-lang/wasp/issues/2889
is that useful?
Yeah, I have a couple questions. Is that used when running the server locally also? I don't see the wasp code there that this is connecting to. Like this doesn't appear to be standalone, right? Also I think this just hits the internal wasp auth apis. I'm still hoping to find one example of parsing the jwt server side using wasps API docs on the client side.
Is that used when running the server locally also?Yes, you have the explanation of how to connect locally in the readme https://github.com/wasp-lang/wasp-expo-app#env-variables-for-development
I don't see the wasp code there that this is connecting to.Mmm what do you mean? It's there in the
wasp-app folder https://github.com/wasp-lang/wasp-expo-app/blob/main/wasp-app/main.wasp
Like this doesn't appear to be standalone, right? Also I think this just hits the internal wasp auth apis. I'm still hoping to find one example of parsing the jwt server side using wasps API docs on the client side.I'm not exactly sure of what you're asking about. What are you trying to accomplish? I understood that you want to have your server written with Wasp and then connect to that through a mobile app in the future, but maybe that's not what you meant. There's no need to parse the JWT anywhere, Wasp takes care of authorizing your app and checks the authorization for the routes you use
authProtected: true on. There's some customization available but I'd like to make sure what you're asking about.GitHub
wasp-expo-app/wasp-app/main.wasp at main · wasp-lang/wasp-expo-app
Example of using Wasp's auth and API in an Expo mobile app - wasp-lang/wasp-expo-app
GitHub
GitHub - wasp-lang/wasp-expo-app: Example of using Wasp's auth and ...
Example of using Wasp's auth and API in an Expo mobile app - wasp-lang/wasp-expo-app
@kapa.ai This is helpful, in the wasp-app, i see this in the main.wasp:
// Custom API endpoints for the Expo app
api getTasksApi {
httpRoute: (GET, "/api/tasks"),
fn: import { getTasks } from "@src/apis",
entities: [Task]
}
api updateTaskAsDoneApi {
httpRoute: (POST, "/api/tasks/:taskId/done"),
fn: import { updateTaskAsDone } from "@src/apis",
entities: [Task]
}
api getUserApi {
httpRoute: (GET, "/api/user"),
fn: import { getUser } from "@src/apis",
entities: [User]
}
what would these api's look like if they required authentication?
@kapa.ai This is helpful, in the wasp-app, i see this in the main.wasp:
// Custom API endpoints for the Expo app
api getTasksApi {
httpRoute: (GET, "/api/tasks"),
fn: import { getTasks } from "@src/apis",
entities: [Task]
}
api updateTaskAsDoneApi {
httpRoute: (POST, "/api/tasks/:taskId/done"),
fn: import { updateTaskAsDone } from "@src/apis",
entities: [Task]
}
api getUserApi {
httpRoute: (GET, "/api/user"),
fn: import { getUser } from "@src/apis",
entities: [User]
}
what would these api's look like if they required authentication?
Let me check the knowledge base for you again. One moment! :books:
----------------------
To require authentication for your custom API endpoints in Wasp, you simply add the
auth: true field to each api declaration in your main.wasp file. This ensures that only authenticated users can access these endpoints, and Wasp will provide a context.user object to your API implementation.
Here’s how your example would look with authentication required:
With auth: true, your API implementation functions (e.g., getTasks, updateTaskAsDone, getUser) will receive a context object that includes the authenticated user (as context.user). You can then use this to further restrict access or personalize responses as needed. If a request is made without authentication, Wasp will automatically reject it.
This is the recommended way to secure custom API endpoints in Wasp, as described in the documentation and API reference Docs: Custom HTTP API Endpoints.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Captain Incredible, 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?@kapa.ai could you also show me what some 'per path' middleware that validated these requests might look like?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Certainly! In Wasp, you can apply middleware to all API routes under a specific path using an
apiNamespace with a middlewareConfigFn. This is called "per-path" middleware. For example, if you want to validate requests for all APIs under /api, you could do the following:
main.wasp
src/apis.js
This middleware will run for all API routes under /api/*. You can implement any validation logic you need inside the middleware function, such as checking headers, tokens, or other request properties.
This approach is described in the Wasp documentation under Configuring Middleware > 3. Customize Per-Path Middleware, which provides a similar example and explains that the middleware is installed at the router level for the specified path.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Captain Incredible, 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?what sort of validation to i need for a protected api here in the src/apis.js file?
@kapa.ai what sort of validation to i need for a protected api here in the src/apis.js file?
Let me check the knowledge base for you again. One moment! :books:
----------------------
For a protected API in Wasp (i.e., one with
- No manual JWT validation is needed in
auth: true), you generally do not need to implement manual authentication validation in your src/apis.js file. When you set auth: true in your main.wasp API declaration, Wasp will automatically attempt to extract and validate the JWT from the request, and will populate context.user if the user is authenticated. If authentication fails, the request will be rejected before your handler is called, so you don't need to check the JWT or user yourself in the middleware or handler code.
Typical validation you might still want to do in your API handler:
- Authorization: Check if the authenticated user (context.user) has permission to perform the requested action (e.g., owns the resource, has a certain role).
- Input validation: Validate the request body, query parameters, or path parameters to ensure they are correct and safe to use.
Example:
You do not need to manually parse or validate the JWT in your handler or middleware—Wasp handles this for you when auth: true is set in the API declaration. If you want to add additional checks (e.g., custom headers, rate limiting), you can do so in middleware, but authentication itself is covered by Wasp’s built-in mechanism Docs: Custom HTTP API Endpoints Docs: Using the context.user object.
If you need more advanced access control (e.g., roles, permissions), you would implement those checks in your handler using the information in context.user Github Issue: Support for Permissions (Access Control).
Summary:- No manual JWT validation is needed in
src/apis.js for protected APIs.
- Use context.user for authorization and implement any business logic or input validation as needed.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Captain Incredible, 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?is the jwt being parsed and validated by default?
@kapa.ai why are you checking for a 'x-custom-header'? doesn't wasp handle this and just give me the validated user by default?
Let me check the knowledge base for you again. One moment! :books:
----------------------
You're absolutely right—if your API is protected with
auth: true in Wasp, you do not need to check for a custom header like x-custom-header for authentication purposes. Wasp automatically handles authentication for you: it validates the user's session (typically via JWT or session cookie), and if the user is authenticated, it provides the context.user object to your API handler. If authentication fails, the request is rejected before your handler runs, so you don't need to manually check headers for authentication.
The example with x-custom-header was just to illustrate how you could add custom middleware for other types of validation (for example, for custom business logic, API versioning, or rate limiting), not for authentication. For authentication, Wasp's built-in mechanism is sufficient when you use auth: true in your API declaration Docs: Custom HTTP API Endpoints Docs: Using the context.user object.
So, for protected APIs, you can rely on Wasp to provide you with a validated user by default—no need to check custom headers for authentication yourself.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Captain Incredible, 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?what type of object does wasp give me for the request?
Wohooo @Captain Incredible, you just became a Waspeteer level 2!
@kapa.ai what type of object does wasp give me for the request?
Let me check the knowledge base for you again. One moment! :books:
----------------------
In Wasp custom API endpoints, the request object provided to your API implementation is the standard Express
Request object. When you define an API function (e.g., export const fooBar = (req, res, context) => { ... }), the first argument, req, is the Express request object, which includes all the usual properties and methods you would expect from Express, such as req.body, req.headers, req.params, etc.
This is explicitly mentioned in the documentation:
After you defined the API, it should be implemented as a NodeJS function that takes three arguments: 1.>req: Express Request object 2.res: Express Response object 3.context: An additional context object injected into the API by Wasp
Docs: Defining the API's NodeJS ImplementationSo, you can use the Express request object as you normally would in any Express-based Node.js application. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
@kapa.ai can you give me a typed api request example for an authed api endpoint?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Certainly! Here is a typed API request example for an authenticated API endpoint in Wasp, using TypeScript. This example is based on the official documentation for custom HTTP API endpoints and authentication.
main.wasp
With
Docs: Defining the API's NodeJS Implementation
Docs: API Reference ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
auth: true, Wasp will ensure only authenticated users can access this endpoint and will provide the context.user object.
src/apis.ts
- req: Express Request object (typed by Express)
- res: Express Response object (typed by Express)
- context: Contains user (the authenticated user) and entities (Prisma models)
This is the recommended and type-safe way to implement an authenticated API endpoint in Wasp using TypeScript.Docs: Defining the API's NodeJS Implementation
Docs: API Reference ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
@kapa.aithis didn't work: api apiNamespace {
middlewareConfigFn: import { middlewareConfig } from "@src/api/_middleware",
path: "/api"
}
whats the correcrt way to create 'per path' api middleware
Let me check the knowledge base for you again. One moment! :books:
----------------------
The correct way to create "per path" API middleware in Wasp is to use the
For more details and examples, see the official docs: Configuring Middleware > 3. Customize Per-Path Middleware. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
apiNamespace declaration in your main.wasp file. The syntax you used is almost correct, but the name after apiNamespace should be an identifier (not a string like api or apiNamespace), and you should specify the path you want the middleware to apply to.
Here’s the correct pattern, based on the official documentation:
main.wasp
- myApiNamespace is just an identifier for this namespace—you can name it whatever you like.
- middlewareConfigFn points to your middleware config function.
- path is the path prefix for which this middleware will be applied.
src/api/_middleware.js
This will apply your middleware to all API routes under /api/*.For more details and examples, see the official docs: Configuring Middleware > 3. Customize Per-Path Middleware. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Captain Incredible, 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?
Hey @Captain Incredible I see you're riffing with the bot. @ tag me if you want some info from me, or when you're done so I can mark this thread as solved.
@Carlos thanks for the reply. I'm struggling with what appears to be getting the user in a custom 'per path' middleware. The docs say that the user should be available on the request object. And it shows how to create the per path oiddleware. But in my case it is undefined.
I see. Have you set the route as needing auth in the wasp file?
My understanding is that it defaults to true
it doesn't
you'll need to set
auth: true in the api routehttps://wasp.sh/docs/advanced/apis and https://wasp.sh/docs/advanced/middleware-config are what I was going off.
huh you're right that it says that
can you check if setting it manually works? we might need to fix that part of the documentation
'''If auth is enabled, this will default to true 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.'''
Yeah, it is interesting how it says " if it is enabled". I wonder what that means
@Carlos, that was the first thing I tried
what's an example request you're sending?
Mind if we move to the other thread that gives a bit more detail? https://discord.com/channels/686873244791210014/1391276067695890644