Overview
The create-event-manager edge function creates a new event manager user account. Event managers have restricted access to specific events within an organization and can only manage check-ins. This function handles user creation, role assignment, and sends a magic link for password setup.
Only organization owners and super admins can create event managers. The function performs authorization checks before proceeding.
Endpoint
POST /functions/v1/create-event-manager
Authentication
Requires a valid Bearer token. The authenticated user must be either:
- The owner of the specified organization
- A super admin
Authorization: Bearer <supabase_access_token>
Request Body
Full name of the event manager. Must be 1-200 characters. HTML tags will be stripped.
Email address for the event manager account. Must be valid email format and max 255 characters.
UUID of the organization this manager will belong to.
Array of event UUIDs the manager should have access to. Can be empty or omitted.
Example Request
curl -X POST 'https://<project-ref>.supabase.co/functions/v1/create-event-manager' \
-H 'Authorization: Bearer <owner_token>' \
-H 'Content-Type: application/json' \
-d '{
"full_name": "Jane Smith",
"email": "[email protected]",
"organization_id": "123e4567-e89b-12d3-a456-426614174000",
"event_ids": [
"abc12345-e89b-12d3-a456-426614174001",
"def67890-e89b-12d3-a456-426614174002"
]
}'
Response
Success Response (200 OK)
Always true for successful creation
UUID of the newly created event manager user
{
"success": true,
"user_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
}
Error Responses
400 Bad Request
Returned when request parameters are invalid or user already exists.
{
"error": "Invalid name"
}
{
"error": "Invalid email"
}
{
"error": "Organization ID is required"
}
{
"error": "A user with this email already exists"
}
401 Unauthorized
Returned when authentication fails.
{
"error": "Unauthorized"
}
403 Forbidden
Returned when the caller is not the organization owner or super admin.
404 Not Found
Returned when the organization is not found.
{
"error": "Organization not found"
}
500 Internal Server Error
Returned when account creation fails.
{
"error": "Failed to create event manager"
}
Implementation Details
From source/supabase/functions/create-event-manager/index.ts:42-56:
if (!full_name || typeof full_name !== "string" ||
full_name.trim().length === 0 || full_name.length > 200) {
return new Response(JSON.stringify({ error: "Invalid name" }), {
status: 400,
});
}
// Strip HTML tags from name
const sanitizedName = full_name.trim().replace(/<[^>]*>/g, "");
if (!email || typeof email !== "string" ||
!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || email.length > 255) {
return new Response(JSON.stringify({ error: "Invalid email" }), {
status: 400,
});
}
User Account Creation
From source/supabase/functions/create-event-manager/index.ts:96-118:
// Generate a secure random password (user will reset via email)
const randomBytes = new Uint8Array(24);
crypto.getRandomValues(randomBytes);
const password = Array.from(randomBytes, (b) =>
b.toString(36).padStart(2, "0")
).join("").slice(0, 32) + "A1!";
// Create user account server-side
const { data: newUser, error: createError } =
await adminClient.auth.admin.createUser({
email: email.trim(),
password,
email_confirm: true,
user_metadata: { full_name: sanitizedName },
});
if (createError || !newUser?.user) {
const msg = createError?.message?.includes("already been registered")
? "A user with this email already exists"
: "Failed to create user account";
return new Response(JSON.stringify({ error: msg }), { status: 400 });
}
Role and Event Assignment
From source/supabase/functions/create-event-manager/index.ts:123-144:
// Assign role + membership
const [roleRes, memberRes] = await Promise.all([
adminClient.from("user_roles").insert({
user_id: newUserId,
role: "event_manager"
}),
adminClient.from("organization_members").insert({
user_id: newUserId,
organization_id,
role: "event_manager",
}),
]);
// Assign events if provided
if (Array.isArray(event_ids) && event_ids.length > 0) {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const validEventIds = event_ids.filter(
(id: unknown) => typeof id === "string" && uuidRegex.test(id)
);
if (validEventIds.length > 0) {
await adminClient.from("event_manager_assignments").insert(
validEventIds.map((eventId: string) => ({
user_id: newUserId,
event_id: eventId
}))
);
}
}
Magic Link for Password Setup
The function sends a magic link email so the event manager can set their own password:
const { error: resetError } = await adminClient.auth.admin.generateLink({
type: "magiclink",
email: email.trim(),
});
Audit Trail
All event manager creation actions are logged:
await adminClient.rpc("log_audit_event", {
_organization_id: organization_id,
_user_id: callerUserId,
_action: "created_event_manager",
_entity_type: "user",
_entity_id: newUserId,
_details: { email: email.trim(), full_name: sanitizedName },
});
Security Features
- HTML Sanitization: Strips HTML tags from name input to prevent XSS
- Email Validation: Validates email format and length
- UUID Validation: Validates all UUID inputs (organization_id, event_ids)
- Authorization Check: Verifies caller is org owner or super admin
- Secure Password Generation: Generates cryptographically secure random password
- Email Confirmation: User account created with email already confirmed
- Magic Link: User sets their own password via secure magic link