Token questions

what are the docs on implementing tokens in opensaas products? how does it work
8 Replies
kapa.ai
kapa.ai5w ago
Hi @ArDev. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- In OpenSaaS products, tokens, specifically JSON Web Tokens (JWT), are used for user authentication. Here's a brief overview of how it works: 1. When a user logs in, their credentials are sent to the OpenSaaS's authentication API. 2. Upon successful authentication, the API generates a JWT containing the user's username and user ID, signs it with a secret key retrieved from the environment, and sends the token back to the client. 3. The client then stores this token securely and uses it for subsequent API calls to authenticate the user. Here's a sample code snippet for generating a JWT:
// generateJwt.ts
import * as jwt from 'jsonwebtoken';
import { Request, Response } from 'express';

async function authenticateUser(username: string, password: string): Promise<{ isAuthenticated: boolean; userId?: string }> {
// TODO: Implement actual user authentication logic here
// This should fetch the user's ID from the database based on the provided username and password
// For demonstration, assuming authentication is successful and returning a mock user ID
return { isAuthenticated: true, userId: 'user123' };
}

export async function generateJwt(req: Request, res: Response): Promise<void> {
const { username, password } = req.body;
try {
const authResult = await authenticateUser(username, password);
if (!authResult.isAuthenticated) {
res.status(401).json({ error: 'Invalid credentials' });
return;
}

// User payload for JWT
const userPayload = { username, userId: authResult.userId };

// Retrieve the secret key from environment variables
const secretKey = process.env.JWT_SECRET_KEY;

if (!secretKey) {
throw new Error('JWT secret key is missing');
}

// Token options
const options = { expiresIn: '1h' }; // Token expires in 1 hour
// Generate the JWT
const token = jwt.sign(userPayload, secretKey, options);

// Send the JWT back to the client
res.json({ token });
} catch (error) {
console.error('Error generating JWT token:', error);
res.status(500).json({ error: 'Internal server error' });
}
}
// generateJwt.ts
import * as jwt from 'jsonwebtoken';
import { Request, Response } from 'express';

async function authenticateUser(username: string, password: string): Promise<{ isAuthenticated: boolean; userId?: string }> {
// TODO: Implement actual user authentication logic here
// This should fetch the user's ID from the database based on the provided username and password
// For demonstration, assuming authentication is successful and returning a mock user ID
return { isAuthenticated: true, userId: 'user123' };
}

export async function generateJwt(req: Request, res: Response): Promise<void> {
const { username, password } = req.body;
try {
const authResult = await authenticateUser(username, password);
if (!authResult.isAuthenticated) {
res.status(401).json({ error: 'Invalid credentials' });
return;
}

// User payload for JWT
const userPayload = { username, userId: authResult.userId };

// Retrieve the secret key from environment variables
const secretKey = process.env.JWT_SECRET_KEY;

if (!secretKey) {
throw new Error('JWT secret key is missing');
}

// Token options
const options = { expiresIn: '1h' }; // Token expires in 1 hour
// Generate the JWT
const token = jwt.sign(userPayload, secretKey, options);

// Send the JWT back to the client
res.json({ token });
} catch (error) {
console.error('Error generating JWT token:', error);
res.status(500).json({ error: 'Internal server error' });
}
}
This code is responsible for handling user authentication and JWT creation in a Wasp application. It includes a mock authentication function that, for demonstration purposes, approves any login attempt and assigns a mock user ID. For more details, you may want to refer to the original discussion on the Wasp Discord server (https://discord.com/channels/686873244791210014/1223328118278983680). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @ArDev, 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?
ArDev
ArDev5w ago
what are the docs on implementing payment tokens in opensaas products? how does it work @kapa.ai
kapa.ai
kapa.ai5w ago
Let me check the knowledge base for you. One moment! :books: ---------------------- In OpenSaaS products, Stripe is used for handling payments. The process of implementing a credit system where payments turn into credits involves the following steps: 1. When creating a Stripe product, you can choose a normal one-time payment for a product. 2. When the payment goes through, you give that user a certain amount of credits. Here's a sample code snippet from the OpenSaaS project that shows how to credit a user with a product payment instead of a subscription:
// stripe.ts
// ...
// if (line_items?.data[0]?.price?.id === process.env.SUBSCRIPTION_PRICE_ID) {
// console.log('Subscription purchased ');
// await context.entities.User.updateMany({
// where: {
// stripeId: userStripeId,
// ...
// stripe.ts
// ...
// if (line_items?.data[0]?.price?.id === process.env.SUBSCRIPTION_PRICE_ID) {
// console.log('Subscription purchased ');
// await context.entities.User.updateMany({
// where: {
// stripeId: userStripeId,
// ...
In this code, the SUBSCRIPTION_PRICE_ID is replaced with CREDITS_PRICE_ID (which you would define in your .env file), and the subscription purchase logic is replaced with the logic for crediting the user. For more details, you may want to refer to the original discussion on the Wasp Discord server (https://discord.com/channels/686873244791210014/1205328655300038766). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @ArDev, 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?
miho
miho5w ago
@Vinny (@Wasp) one for you maybe
Vinny (@Wasp)
Vinny (@Wasp)4w ago
hey @ArDev did you read the open saas docs on creating a new (one-time payment) product?
Vinny (@Wasp)
Vinny (@Wasp)4w ago
OpenSaaS.sh
Stripe Integration
Open SaaS is a free, open-source, full-stack SaaS starter kit for React + NodeJS.
Vinny (@Wasp)
Vinny (@Wasp)4w ago
Once you create the one-time payment credits-based product, you add the product to your environment variables. You can find the configuration for hte plans/products in src/payment/plans.ts --> https://github.com/wasp-lang/open-saas/blob/main/template/app/src/payment/plans.ts#L18-L31 At the moment, there is only one credits-based product, and you'll see that it gives the user 10 new credits in the effect.amount property:
export const paymentPlans: Record<PaymentPlanId, PaymentPlan> = {
// ...
[PaymentPlanId.Credits10]: {
getStripePriceId: () => requireNodeEnvVar('STRIPE_CREDITS_PRICE_ID'),
effect: { kind: 'credits', amount: 10 },
},
};
export const paymentPlans: Record<PaymentPlanId, PaymentPlan> = {
// ...
[PaymentPlanId.Credits10]: {
getStripePriceId: () => requireNodeEnvVar('STRIPE_CREDITS_PRICE_ID'),
effect: { kind: 'credits', amount: 10 },
},
};
Y these credits then get deducted every time the user makes a generation on the Demo App (src/demo-ai-app/operations.ts):
} else if (context.user.credits && !context.user.subscriptionStatus) {
console.log('decrementing credits');
await context.entities.User.update({
where: { id: context.user.id },
data: {
credits: {
decrement: 1,
},
},
});
}
} else if (context.user.credits && !context.user.subscriptionStatus) {
console.log('decrementing credits');
await context.entities.User.update({
where: { id: context.user.id },
data: {
credits: {
decrement: 1,
},
},
});
}
ArDev
ArDev4w ago
thanks!
Want results from more Discord servers?
Add your server