Admin Created Users

I need the Admins to be able to create users which would trigger an email confirmation. I also dont want the users to be able to create their own account. How can I do this please?
7 Replies
kapa.ai
kapa.ai3mo ago
Hi @alphadog2584. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Wasp’s built-in authentication flow is designed for user self-signup, but you can customize it to fit your requirements: 1. Prevent User Self-Signup:
Wasp does not provide a direct setting to disable the default signup page, but you can control access to the signup route in your frontend. For example, you can remove or hide the signup page and its links from the UI, and ensure only admins have access to user creation functionality. 2. Admin-Created Users with Email Confirmation:
You can implement a custom signup action that only admins can trigger. The Wasp docs provide an example of a custom signup action for email authentication, which includes sending a verification email to the new user. You can adapt this logic so that only admins can call this action, and regular users cannot access it. Here’s a high-level approach: - Create a custom signup action (as shown in the docs) that performs the necessary validations and sends a verification email to the new user. - Restrict access to this action so only admins can call it (e.g., by checking the admin’s role in the action’s context). - Remove or disable the public signup page/route so users cannot create accounts themselves. Example (simplified, based on the docs):
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidEmail,
createProviderId,
sanitizeAndSerializeProviderData,
findAuthIdentity,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'

export const adminCreateUser = async (args, context) => {
// Check if the current user is an admin
if (!context.user || context.user.role !== 'admin') {
throw new HttpError(403, 'Only admins can create users.')
}

ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)
// ... (rest of the logic as in the custom signup action)
}
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidEmail,
createProviderId,
sanitizeAndSerializeProviderData,
findAuthIdentity,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'

export const adminCreateUser = async (args, context) => {
// Check if the current user is an admin
if (!context.user || context.user.role !== 'admin') {
throw new HttpError(403, 'Only admins can create users.')
}

ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)
// ... (rest of the logic as in the custom signup action)
}
You can find the full example and more details in the Wasp docs on creating a custom sign-up action. Note: You will need to add a role field to your User entity and implement role-based checks, as described in this Discord thread. Summary:
- Hide/remove the public signup page. - Implement a custom signup action callable only by admins. - Use the custom signup logic to send email confirmations to new users. If you need more detailed code or step-by-step instructions, let me know! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @alphadog2584, 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?
alphadog2584
alphadog2584OP3mo ago
@kapa.ai can I get more detail
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Certainly! Here’s a more detailed breakdown of how you can achieve “admin-created users with email confirmation” and prevent users from creating their own accounts, based strictly on the available Wasp documentation and community discussions: --- 1. Preventing User Self-Signup Wasp does not provide a built-in flag to disable the default signup page, but you can control this at the UI level: - Remove or hide the signup page/route from your app’s navigation and UI. - Do not expose the signup form to non-admin users. - If you have a custom signup action, ensure it is not called from any public-facing component. --- 2. Admin-Created Users with Email Confirmation You can create a custom signup action that only admins can call. The Wasp docs provide a template for a custom signup action that sends an email verification link to the new user. You can adapt this for your admin-only use case. Example (TypeScript, adapted from docs):
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidEmail,
createProviderId,
sanitizeAndSerializeProviderData,
findAuthIdentity,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'
import type { CustomSignup } from 'wasp/server/operations'

type CustomSignupInput = {
email: string
password: string
}
type CustomSignupOutput = {
success: boolean
message: string
}

export const adminCreateUser: CustomSignup<CustomSignupInput, CustomSignupOutput> = async (args, context) => {
// Check if the current user is an admin
if (!context.user || !context.user.isAdmin) {
throw new Error('Only admins can create users.')
}

ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)
const providerId = createProviderId('email', args.email)
const existingAuthIdentity = await findAuthIdentity(providerId)

if (existingAuthIdentity) {
return { success: false, message: 'User already exists.' }
} else {
const newUserProviderData = await sanitizeAndSerializeProviderData<'email'>({
hashedPassword: args.password,
isEmailVerified: false,
emailVerificationSentAt: null,
passwordResetSentAt: null,
})
await createUser(
providerId,
newUserProviderData,
{} // Add any additional user fields here
)

const verificationLink = await createEmailVerificationLink(args.email, '/email-verification')
await sendEmailVerificationEmail(
args.email,
{
from: { name: "My App Postman", email: "[email protected]" },
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>`,
}
)
return { success: true, message: 'User created and verification email sent.' }
}
}
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidEmail,
createProviderId,
sanitizeAndSerializeProviderData,
findAuthIdentity,
createUser,
createEmailVerificationLink,
sendEmailVerificationEmail,
} from 'wasp/server/auth'
import type { CustomSignup } from 'wasp/server/operations'

type CustomSignupInput = {
email: string
password: string
}
type CustomSignupOutput = {
success: boolean
message: string
}

export const adminCreateUser: CustomSignup<CustomSignupInput, CustomSignupOutput> = async (args, context) => {
// Check if the current user is an admin
if (!context.user || !context.user.isAdmin) {
throw new Error('Only admins can create users.')
}

ensureValidEmail(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)
const providerId = createProviderId('email', args.email)
const existingAuthIdentity = await findAuthIdentity(providerId)

if (existingAuthIdentity) {
return { success: false, message: 'User already exists.' }
} else {
const newUserProviderData = await sanitizeAndSerializeProviderData<'email'>({
hashedPassword: args.password,
isEmailVerified: false,
emailVerificationSentAt: null,
passwordResetSentAt: null,
})
await createUser(
providerId,
newUserProviderData,
{} // Add any additional user fields here
)

const verificationLink = await createEmailVerificationLink(args.email, '/email-verification')
await sendEmailVerificationEmail(
args.email,
{
from: { name: "My App Postman", email: "[email protected]" },
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>`,
}
)
return { success: true, message: 'User created and verification email sent.' }
}
}
This is based on the official Wasp docs for custom email signup. --- 3. How to Use This - Expose this action only in your admin dashboard or admin-only UI. - Do not provide a public signup form. - When an admin wants to create a user, they fill out the form and trigger this action. - The new user receives a verification email and completes their registration. --- 4. Additional Notes - You may need to add an isAdmin or role field to your User entity if you haven’t already, as discussed in the Discord thread about roles and admin dashboards. - The knowledge sources do not mention a built-in way to completely disable the signup endpoint, so UI and action-level restrictions are the recommended approach. --- If you need help wiring this up in your Wasp app, let me know which part you’re working on and I can provide more focused guidance! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @alphadog2584, 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?
Vinny (@Wasp)
Vinny (@Wasp)3mo ago
@alphadog2584 did the bot answer your question?
alphadog2584
alphadog2584OP3mo ago
@Vinny (@Wasp) I amstill trying to get my head around wasp, I am not sure which files to change , I think there is a mistake in the doco https://wasp.sh/docs/auth/advanced/custom-auth-actions Email main.wasp action customSignup { fn: import { signup } from "@src/auth/signup.js", } Should be: action customSignup { fn: import { signup } from "@src/auth/signup.ts", } Am I wrong?
Custom sign-up actions | Wasp
If you need to deeply hook into the sign-up process, you can create your own sign-up action and customize the code to, for example, add extra validation, store more data, or otherwise call custom code at registration time.
Vinny (@Wasp)
Vinny (@Wasp)3mo ago
you can use js or ts in your app. whatever you prefer.
Vinny (@Wasp)
Vinny (@Wasp)3mo ago
Have you gone through the quick 20 min intro tutorial? That should help get the basics down. For creating an admin and not allowing other users to login, you need to add an isAdmin flag to your user model in schema.prisma. Then, for the non admin users, you have a few options: 1. use one of the Auth Hooks to prevent normal users/users that have not been invited from logging in. 2. Allow all users to log in. Add properties like hasUserBeenInvited and isSignupComplete to the user entity and in the root app component (eg. main.tsx) use the useAuth hook to check their status and allow them entry to the app, or redirect them to the correct page to complete registration or whatever.
import { useAuth } from 'wasp/client/auth'
import { Link } from 'react-router-dom'
import Todo from '../Todo'

export function Main() {
const { data: user } = useAuth()

if (!user.isSignupComplete) {
return (
<span>
<Link to='/finish-signup'>Finish registering here</Link<
</span>
)
} else {
return (
<span>
Welcome to the app!
</span>
)
}
}
import { useAuth } from 'wasp/client/auth'
import { Link } from 'react-router-dom'
import Todo from '../Todo'

export function Main() {
const { data: user } = useAuth()

if (!user.isSignupComplete) {
return (
<span>
<Link to='/finish-signup'>Finish registering here</Link<
</span>
)
} else {
return (
<span>
Welcome to the app!
</span>
)
}
}
Auth Hooks | Wasp
Auth hooks allow you to "hook into" the auth process at various stages and run your custom code. For example, if you want to forbid certain emails from signing up, or if you wish to send a welcome email to the user after they sign up, auth hooks are the way to go.
Overview | Wasp
Auth is an essential piece of any serious application. That's why Wasp provides authentication and authorization support out of the box.

Did you find this page helpful?