How to generate Authorization header JWT token for custom API endpoint?
I've created operation which generates JWT token which is sent to my chrome extension.
The main goal is to access context.user for my custom API endpoint to verify if the user has a paid plan.
I've tried many combinations, using userId, username, and even config.auth.jwtSecret instead of my JWT_SECRET_KEY in env.server, but none of these work with auth:true for api endpoint in a Postman request that includes a generated bearer token.
What's the right format to sign a JWT token for it to work with a custom API endpoint to access context.user?
EDIT: I used the client-side sessionId for a custom API endpoint; however, some questions still remain
53 Replies
Hi @sion0921. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
To generate a JWT token for a custom API endpoint in a Wasp application, you can create a function like
generateJwt
in your server-side code. This function will handle user authentication and JWT creation. Here's an example of how you might implement this function:
This function first authenticates the user. If the authentication is successful, it creates a payload with the user's username and ID, signs a JWT with this payload and a secret key, and sends the JWT back to the client.
You can then define this function as an API endpoint in your main.wasp
file:
To use this API endpoint, you can send a POST request to /api/generate-jwt
with the user's credentials in the request body. The server will respond with a JWT that you can use for subsequent API calls.
Please note that the authenticateUser
function in this example is a mock function that approves any login attempt and assigns a mock user ID. You should replace this with your actual user authentication logic.
Sources:
- Discord support thread: Best Practices for Implementing Auth System in Chrome Extension Connected to OpenSaaS > Answers Part 2 (https://discord.com/channels/686873244791210014/1223328118278983680)
- Discord support thread: Best Practices for Implementing Auth System in Chrome Extension Connected to OpenSaaS > Answers Part 3 (https://discord.com/channels/686873244791210014/1223328118278983680)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @sion0921, 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, I've updated the original post. Can you regenerate your answer?
@kapa.ai I've updated the original post. Can you regenerate your answer?
Let me check the knowledge base for you. One moment! :books:
----------------------
I'm sorry, but I can't provide the help you're looking for.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @sion0921, 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?
help?
@miho
I found a post, so the correct format is to send sessionId as a Bearer token? How long before it expires?
is your questoin solved?
Ill get back to you when I test it**
Wohooo @sion0921, you just became a Waspeteer level 1!
@Sven Hell yea! It did work
niceee
could you provide me maybe the code snippets on how you just did it?
i have been struggling with this for really long
Sure
goat man
🐐
@Sven Question, are you working on a chrome extension as well?
yessss
Aight, then I got ya
Basically, whenever a user installs an extension, they must log in to use it
This will redirect to the login page or, if you are already logged in, to the extension activation page. This page is crucial because it delivers the bearer token for your extension in the proper format.
Within this page, use the session ID to send it over to your Chrome extension as follows:
Use background.js script to save token in browser storage and utilize it for requests to custom API endpoints.
ahh okay and do you have something in it that makes the token expire?
No idea. I just got it working though. I'll test and see.
Wohooo @sion0921, you just became a Waspeteer level 2!
ahh alright keep me posted man thx
do i need to import any thing to be able to send a message through my webapp SaaS
I logged out and back in, yet the session ID bearer token remained active. After restarting both the Wasp server and the database, everything functioned as expected. Generating a new session ID didn't invalidate the old one, which continued to work. Initially, everything appeared fine, but after approximately ten minutes, it failed, requiring me to reactivate the extension 🤷♀️
@miho "Is it possible to prevent getSessionId from 'wasp/client/api' from expiring? 👉👈
so activating it again with the extension?
well what you could do is get subscription data from the endpoint? no?
but the main thing i am struggling with is protecting my endpoints such that people cant access data if they have no subscription
Other people have accomplished this using custom endpoints and email verification. I cannot incorporate extensive custom logic into every request because my extension needs to respond quickly. Hence, the name of my SaaS is SpellFast. My only feasible option is to implement the excisting Wasp authentication mechanism to maintain speed.
Well, it's working with my method ✅ You can fetch subscription status. I've tested both with my extension and with Postman already 100 times. Only once did I receive an "Unauthenticated" response, and I'm unsure why this occurred
okay so how are you handeling now to check somethimes if user is still authed?
also do you protect any of your endponts?
😆
how does that endpoint even access contextUser?
does this request involve a JWT token?
@Sven The purpose of this thread is to understand how to access 'context.user'. And I think its partially solved ✅ You can access it from the frontend using 'getSessionId()', then from your Chrome extension when making a request to your custom API endpoint. You will need to use that token to gain access to 'context.user'.
Here's how I send the fetch request (google chrome extension code):
Alright clear
Would this also be a way, watch kapa’s answer:
@kapa.ai How to secure an api endpoint in wasp 0.14 with jwt tokens?
Let me check the knowledge base for you. One moment! :books:
----------------------
To secure an API endpoint in Wasp with JWT tokens, you need to create a function that generates the JWT token and then use this token for subsequent API calls. Here's a step-by-step guide:
1. Create a function to generate JWT token: This function will handle user authentication and JWT creation. Here's an example of how you might implement this function:
This function first authenticates the user. If the authentication is successful, it creates a payload with the user's username and ID, signs a JWT with this payload and a secret key, and sends the JWT back to the client.
2. Define the function as an API endpoint in your
main.wasp
file:
This will create a new API endpoint at /api/generate-jwt
that you can use to generate JWT tokens.
3. Use the JWT token for subsequent API calls: Once you have the JWT token, you can include it in the Authorization
header of your API calls to secure them. The server can then verify the JWT token and only process the API call if the token is valid.
Please note that the authenticateUser
function in this example is a mock function that approves any login attempt and assigns a mock user ID. You should replace this with your actual user authentication logic.
Also, remember to replace 'your-secret-key'
with your actual secret key when signing the JWT. This secret key should be kept secure and not exposed in your client-side code.
Sources:
- Discord support thread: Best Practices for Implementing Auth System in Chrome Extension Connected to OpenSaaS > Answers Part 2 (https://discord.com/channels/686873244791210014/1223328118278983680)
- Discord support thread: Best Practices for Implementing Auth System in Chrome Extension Connected to OpenSaaS > Answers Part 3 (https://discord.com/channels/686873244791210014/1223328118278983680)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Sven, 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?
This code snippet from the AI answer will generate a JWT token in a completely different format compared to what you get from sessionId.
So, ynfortunately, no, this method won't generate a valid token to access context.user.
Ah okay
But if i replace it with the sessionid token gen, wouldn’t it work then
I think the session ID is limited to the client side of the website. While I might be mistaken, I haven't discovered a method to generate it on the server side.
Ah
I would greatly appreciate it if @miho could provide input on whether using getSessionId from 'wasp/client/api' as the primary method for authentication and authorization is appropriate. Mate @miho could you please take a look at this issue?
We are in different timezones, sorry for the wait 🙂
getSessionId
is the correct way to get the current session, it's stored in the DB and it's a string that identified you as the user.
On the note of expiry, the session expires after 30 days (Lucia's default: https://lucia-auth.com/basics/sessions) and they are extend when used automatically.
If you need a special auth mechanism to not expire, you can always have a custom API endpoint that will return a special token that doesn't expire and you keep in the database. Or you could craft a JWT token that has a long lifetime and you maybe have a refresh API endpoint that gives you the ability to get new valid JWT tokens. It's really up to you 🙂how do you use these :
and how do u declare chrome
SO now what i have is this:
Then this token will be stored in the chrome extension, now how would i make sure that only paying users can do certain stuff and use certain endpoints from my saas (through the chrome ext)
Wohooo @Sven, you just became a Waspeteer level 9!
@kapa.ai
[ Wasp ] ext-src/ChromeExtensiePage.tsx(10,20): error TS2304: Cannot find name 'chrome'.
[ Wasp ] ext-src/ChromeExtensiePage.tsx(36,7): error TS2304: Cannot find name 'chrome'.
[ Wasp ] ext-src/ChromeExtensiePage.tsx(40,15): error TS2304: Cannot find name 'chrome'.
[ Wasp ] ext-src/ChromeExtensiePage.tsx(41,54): error TS2304: Cannot find name 'chrome'.
Let me check the knowledge base for you. One moment! :books:
----------------------
The error messages you're seeing are TypeScript compiler errors. They're saying that the TypeScript compiler can't find the name 'chrome'. This is because the
chrome
object is part of the Chrome extension APIs, and it's not part of the standard JavaScript or TypeScript libraries, so the TypeScript compiler doesn't know about it by default.
To fix these errors, you need to include the Chrome extension type definitions in your project. These type definitions are available in the @types/chrome
package. Here's how you can add them:
1. Install the @types/chrome
package by running the following command in your project directory:
2. Then, in your tsconfig.json
file (which is the configuration file for the TypeScript compiler), add "chrome"
to the "types"
array, like this:
This tells the TypeScript compiler to include the Chrome extension type definitions when it's checking your code.
After you've done this, the TypeScript compiler should know about the chrome
object and you should no longer see the TS2304: Cannot find name 'chrome'
errors.
Please note that this solution assumes you're using npm as your package manager and that you have a tsconfig.json
file in your project. If your setup is different, you might need to adjust the steps accordingly.
Unfortunately, I can't provide links to the relevant documentation or code because they're not included in the knowledge sources provided.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @Sven, 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?Any help on this?
Team doesn't work over the weekend 😄 @sodic will get to you
Yeah i know was just to let you jow
Hey @Sven , could you summarize exactly what you need help with to save me the trouble of reading the thread? Thanks!
I have a chrome extension. Now on my saas when a logged in user presses a button on my page (auth=true) it sends the session id to the chrome extension and is stored there.
This as described above is the only thing i now have. My question:
Then this token will be stored in the chrome extension, now how would i make sure that only paying users can do certain stuff and use certain endpoints from my saas (through the chrome ext)
Yessss
I see
So, a token provides you with Authentication (who are they).
What you need is Authorization (what are they allowed to do). To authorize users, you'll need to save their privileges in the database (for example, by adding a
is_paying
column to the user.
Then:
1. The user sends a request with the token
2. The app connects the token to the user's database entry
3. The app can see whether that token belongs to a paying userAhh but is there not already an entry in the user dh that does this? Subscription plan, subscription status
And what token? A jwt token? Now i have sessionId
Sorry, yes, that, session ID
Yes, you're right
you just need to query that then
So, a user sends a token from the chrome extension, you connect to the user's db entry
And you see what you want to allow them to do
Okay then, do you have a good way of testing it with subscription plans? Do i need to setup whole stripe then?
Or can i do a test something? I have stripe already but test thing i think
Oh and also, how would i properly check on my saas side to only send the token over if the person is authorized + subscriped to a specific plan? Is there any nice shortcut for checking this
You'll have to implement this logic yourself, so it's completely up to you.
Is there any nice shortcut for checking thisIf you mean "does Wasp offer something out of the box," then the answer is unfortunately no. I'd do it like I described above. Authenticate the user, authorize them, and then send them the appropriate token. Afterwards, verify the token.
Okay then, do you have a good way of testing it with subscription plans? Do i need to setup whole stripe then?Again, you can test/mock it however you want (just like you'd do with any other feature). If you're new to this, I recommend searching online without mentioning wasp. That's the best way to find solutions, because it's a pretty general problem, not wasp-specific.
So far, it looks good. However, you need to add some additional code to the background.js script to save the token in browser storage.