Token questions
what are the docs on implementing tokens in opensaas products? how does it work
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.src/payment/plans.ts --> https://github.com/wasp-lang/open-saas/blob/main/template/app/src/payment/plans.ts#L18-L31effect.amount property:src/demo-ai-app/operations.ts):createUser function in your server-side code:verify function from the JWT library.waspc/data/Generator/templates/server/core/auth.jswaspc/data/Generator/templates/react-app/src/api.jsmain.wasp file:signup.js file, you'll need to implement the token generation logic:localStorage. This allows the token to persist across page reloads and browser sessions. Wasp Auth Overview (https://wasp-lang.dev/docs/auth/overview#sessions) mentions:localStorage on the client and in the database on the server."localStorage. When users log out, Wasp deletes the session from both the database and localStorage.Auth entityAuthIdentity entitySession entitySession entity is likely where the session information is stored, which is used to validate the user's authentication status.api createUser {
fn: import { createUser } from "@src/auth/createUser.js",
httpRoute: (POST, "/api/create-user")
}action customSignup {
fn: import { signup } from "@src/auth/signup.js",
entities: [User]
}SUBSCRIPTION_PRICE_IDCREDITS_PRICE_IDsrc/payment/plans.tseffect.amountsrc/demo-ai-app/operations.tsverifywaspc/data/Generator/templates/server/core/auth.jswaspc/data/Generator/templates/react-app/src/api.jsAuthAuthIdentitySessionSession// 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,
// ...export const paymentPlans: Record<PaymentPlanId, PaymentPlan> = {
// ...
[PaymentPlanId.Credits10]: {
getStripePriceId: () => requireNodeEnvVar('STRIPE_CREDITS_PRICE_ID'),
effect: { kind: 'credits', amount: 10 },
},
}; } 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,
},
},
});
}// src/auth/createUser.js
import {
createProviderId,
sanitizeAndSerializeProviderData,
createUser as waspCreateUser
} from 'wasp/server/auth'
import * as jwt from 'jsonwebtoken'
export const createUser = async (args, context) => {
try {
const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})
const user = await waspCreateUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
// Generate JWT token
const secretKey = process.env.JWT_SECRET_KEY
if (!secretKey) {
throw new Error('JWT secret key is missing')
}
const token = jwt.sign({ userId: user.id }, secretKey, { expiresIn: '1h' })
return {
success: true,
message: 'User created successfully',
token
}
} catch (e) {
return {
success: false,
message: e.message
}
}
}import {
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
} from 'wasp/server/auth'
import * as jwt from 'jsonwebtoken'
export const signup = async (args, context) => {
try {
const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})
const user = await createUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
// Generate JWT token
const secretKey = process.env.JWT_SECRET_KEY
if (!secretKey) {
throw new Error('JWT secret key is missing')
}
const token = jwt.sign({ userId: user.id }, secretKey, { expiresIn: '1h' })
return {
success: true,
message: 'User created successfully',
token
}
} catch (e) {
return {
success: false,
message: e.message
}
}
}