W
Wasp20h ago
Dada

Generate Email Verification Link/ SendVerificationEmail function

Hello guys , is there a way to generate email verificationLink ? i created a custom signup action , i want to generate a verificationLink to send it as an email using emailSender or even better if there is a function i can call in my actions like sendVerificationEmail or something.
5 Replies
kapa.ai
kapa.ai20h ago
Hi @Dada. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, Wasp provides built-in functions for generating email verification links and sending verification emails in custom signup actions. Here's how you can do it: Generating Email Verification Links In your custom signup action, you can use these two functions from Wasp: 1. createEmailVerificationLink - Generates a verification link 2. sendEmailVerificationEmail - Sends the verification email Here's an example of how to implement this in a custom signup action:
import {
ensureValidEmail,
ensurePasswordIsPresent,
ensureValidPassword,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'

export const signup = async (args, _context) => {
ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
const providerId = createProviderId('email', args.email)
// ... other signup logic ...
// Generate verification link
const verificationLink = await createEmailVerificationLink(args.email, '/email-verification');

// Send verification email
try {
await sendEmailVerificationEmail(
args.email,
{
from: {
name: "My App Postman",
},
to: args.email,
subject: "Verify your email",
text: `Click the link below to verify your email: ${verificationLink}`,
html: `
<p>Click the link below to verify your email</p>
<a href="${verificationLink}">Verify email</a>
`,
}
);
} catch (e) {
console.error("Failed to send email verification email:", e);
throw new HttpError(500, "Failed to send email verification email.");
}

// ... rest of your signup logic ...
} catch (e) {
return {
success: false,
message: e.message,
}
}

return {
success: true,
message: 'User created successfully',
}
}
import {
ensureValidEmail,
ensurePasswordIsPresent,
ensureValidPassword,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'

export const signup = async (args, _context) => {
ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
const providerId = createProviderId('email', args.email)
// ... other signup logic ...
// Generate verification link
const verificationLink = await createEmailVerificationLink(args.email, '/email-verification');

// Send verification email
try {
await sendEmailVerificationEmail(
args.email,
{
from: {
name: "My App Postman",
},
to: args.email,
subject: "Verify your email",
text: `Click the link below to verify your email: ${verificationLink}`,
html: `
<p>Click the link below to verify your email</p>
<a href="${verificationLink}">Verify email</a>
`,
}
);
} catch (e) {
console.error("Failed to send email verification email:", e);
throw new HttpError(500, "Failed to send email verification email.");
}

// ... rest of your signup logic ...
} catch (e) {
return {
success: false,
message: e.message,
}
}

return {
success: true,
message: 'User created successfully',
}
}
The createEmailVerificationLink function takes the user's email and the client route path where the user will be redirected to verify their email. Setting Up Email Verification For this to work, you need to: 1. Set up email authentication in your Wasp app 2. Configure an email sender 3. Set up the email verification route Make sure you have the email verification route defined in your main.wasp file:
route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
page EmailVerificationPage {
component: import { EmailVerification } from "@src/pages/auth.jsx",
}
route EmailVerificationRoute { path: "/email-verification", to: EmailVerificationPage }
page EmailVerificationPage {
component: import { EmailVerification } from "@src/pages/auth.jsx",
}
And configure an email sender:
app myApp {
// ...
emailSender: {
provider: Dummy, // Use a real provider in production
}
}
app myApp {
// ...
emailSender: {
provider: Dummy, // Use a real provider in production
}
}
You can use the built-in VerifyEmailForm component from Wasp to handle the verification process on the client side. Learn more about email authentication in Wasp Hope this helps with your implementation! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Dada, 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?
Dada
DadaOP19h ago
oh great @kapa.ai what are the arguments createUser function expects ?
kapa.ai
kapa.ai19h ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources, the createUser function in Wasp expects the following arguments: 1. providerId: A string that uniquely identifies the user in your app. It's a combination of the provider name and the provider user ID, which you can create using the createProviderId function. 2. providerData: A serialized JSON string containing provider-specific data. This is typically created using the sanitizeAndSerializeProviderData function, which handles things like password hashing. 3. additionalUserData: An optional object containing any additional data you want to store on the User entity. Here's an example of how to use the createUser function in a custom signup action:
const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})

await createUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})

await createUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
This is equivalent to using Prisma's User.create method with a more complex structure:
await User.create({
data: {
auth: {
create: {
identities: {
create: {
providerName: 'username',
providerUserId: args.username,
providerData,
},
},
}
},
}
})
await User.create({
data: {
auth: {
create: {
identities: {
create: {
providerName: 'username',
providerUserId: args.username,
providerData,
},
},
}
},
}
})
The createUser function is a convenience wrapper that handles the complexity of creating the proper relationships between the User, Auth, and AuthIdentity entities in your database. Auth Entities documentation provides more details about how to use this function in custom signup actions. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Dada, 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?
Dada
DadaOP19h ago
@kapa.ai what kind of password hash should i use in registration , because login is failing , i used const hashedPassword = await bcrypt.hash(args.password, 10);
kapa.ai
kapa.ai19h ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You shouldn't use bcrypt directly in your Wasp app for password hashing. Wasp provides built-in functions that handle password hashing for you automatically. When creating a user or updating a password, you should use Wasp's sanitizeAndSerializeProviderData function, which will handle the password hashing internally. Here's the correct way to handle passwords in a signup action:
import {
ensurePasswordIsPresent,
ensureValidPassword,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
} from 'wasp/server/auth'

export const signup = async (args, _context) => {
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
const providerId = createProviderId('username', args.username) // or 'email' if using email auth
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password, // Pass the plain text password here
})

await createUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
} catch (e) {
// Handle error
}
}
import {
ensurePasswordIsPresent,
ensureValidPassword,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
} from 'wasp/server/auth'

export const signup = async (args, _context) => {
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
const providerId = createProviderId('username', args.username) // or 'email' if using email auth
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password, // Pass the plain text password here
})

await createUser(
providerId,
providerData,
// Any additional data you want to store on the User entity
{},
)
} catch (e) {
// Handle error
}
}
The key point is that you should pass the plain text password to the hashedPassword field in the sanitizeAndSerializeProviderData function. Despite the field name being hashedPassword, you should provide the plain text password - Wasp will handle the hashing for you. If you're updating a password, you can use the updateAuthIdentityProviderData function:
await updateAuthIdentityProviderData(providerId, providerData, {
hashedPassword: args.password, // Plain text password
})
await updateAuthIdentityProviderData(providerId, providerData, {
hashedPassword: args.password, // Plain text password
})
This approach ensures that your passwords are hashed consistently with Wasp's authentication system, which is why your login was failing when using bcrypt directly. Password Hashing documentation provides more details about how to properly handle passwords in Wasp. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Dada, 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?

Did you find this page helpful?