Skip to main content

Overview

The Users API provides authentication helpers, user profile management, and account settings for both organizers and attendees on the EventPalour platform.

Get Current User

Retrieve the currently authenticated user.
import { getCurrentUser } from '@/app/actions/auth';

const result = await getCurrentUser();

if (result) {
  console.log('User:', result.user.email);
  console.log('Session:', result.session.id);
} else {
  console.log('Not authenticated');
}

Response

user
User
User object containing:
  • id - User identifier
  • email - Email address
  • username - Display name
  • avatar - Avatar URL
  • platform_role - Role: organizer or attendee
  • email_verified - Email verification status
  • registered_2fa - 2FA enabled status
  • created_at - Account creation date
session
Session
Session object with session ID and metadata
Returns null if user is not authenticated.

Require Authentication

Enforce authentication or redirect to sign-in.
import { requireAuth } from '@/app/actions/auth';

const { user, session } = await requireAuth();
// User is guaranteed to be authenticated here
If user is not authenticated, automatically redirects to /auth/sign-in.

Usage in Server Components

export default async function DashboardPage() {
  const { user } = await requireAuth();
  
  return (
    <div>
      <h1>Welcome, {user.username}</h1>
    </div>
  );
}

Platform Roles

EventPalour has two primary user roles:
Event OrganizersOrganizers can:
  • Create and manage workspaces
  • Create events (free and paid)
  • Invite team members
  • View analytics and revenue
  • Manage ticket sales
  • Access organizer dashboard
platform_role: PlatformRole.ORGANIZER
KYC Required: Organizers must complete KYC verification to create paid events.

Require Platform Role

Enforce specific platform role or redirect.
import { requireRole } from '@/app/actions/auth';
import { PlatformRole } from '@/lib/db/schema/enums';

const { user } = await requireRole(PlatformRole.ORGANIZER);
// User is guaranteed to be an organizer

Role Redirection Logic

1

Check Authentication

If not authenticated, redirect to /auth/sign-in
2

Check Platform Role

If no role set, redirect to /auth/onboarding
3

Check Admin Status

If user is platform admin, redirect to /admin
4

Validate Role Match

If role doesn’t match required:
  • Attendees → /dashboard
  • Organizers → /workspace/{workspaceId}
if (user.platform_role !== requiredRole) {
  if (user.platform_role === PlatformRole.ATTENDEE) {
    redirect('/dashboard');
  } else if (user.platform_role === PlatformRole.ORGANIZER) {
    const workspace = await getUserWorkspace(user.id);
    redirect(`/workspace/${workspace.id}`);
  }
}

Get User Workspaces

Retrieve all workspaces a user belongs to.
import { getUserWorkspaces } from '@/app/actions/auth';

const workspaces = await getUserWorkspaces(userId);

workspaces.forEach(({ workspace, role, isOwner }) => {
  console.log(`${workspace.name} - ${role} ${isOwner ? '(Owner)' : ''}`);
});

Response

Array of workspace memberships:
workspace
object
Workspace details:
  • id - Workspace ID
  • name - Workspace name
  • image_url - Logo URL
  • invite_code - Invite code
  • created_at - Creation date
role
WorkspaceRole
User’s role: admin, moderator, or member
isOwner
boolean
True if user owns the workspace

Validate Workspace Access

Check if user has access to a workspace.
import { validateWorkspaceAccess } from '@/app/actions/auth';

const { user, workspace, workspaceRole } = 
  await validateWorkspaceAccess('wks_abc123');

console.log(`Access granted as ${workspaceRole}`);

Access Validation Rules

If user is the workspace owner:
  • Automatically granted admin role
  • Full access to all features
if (workspace.user_id === user.id) {
  return { workspaceRole: 'admin' };
}
If user is a workspace member:
  • Role determined by membership record
  • Access based on role permissions
If user is not a member:
  • Redirected to first available workspace
  • Or to /workspace/unauthorized if no workspaces

Require Workspace Role

Enforce minimum workspace role.
import { requireWorkspaceRole } from '@/app/actions/auth';
import { WorkspaceRole } from '@/lib/db/schema/enums';

const { user, workspace, workspaceRole } = 
  await requireWorkspaceRole('wks_abc123', WorkspaceRole.MODERATOR);

// User has at least moderator role

Role Hierarchy

const roleHierarchy = {
  member: 1,      // View-only access
  moderator: 2,   // Can create events
  admin: 3        // Full management
};

// Check if user has required role or higher
if (roleHierarchy[userRole] < roleHierarchy[requiredRole]) {
  redirect('/workspace/unauthorized');
}

Check Workspace Role

Check role without redirecting (for conditional rendering).
import { checkWorkspaceRole } from '@/app/actions/auth';
import { WorkspaceRole } from '@/lib/db/schema/enums';

const result = await checkWorkspaceRole(
  'wks_abc123',
  WorkspaceRole.ADMIN
);

if (result.hasAccess) {
  // Show admin-only features
}

Response

hasAccess
boolean
True if user has required role or higher
user
User
User object (if access granted)
workspace
Workspace
Workspace object (if access granted)
workspaceRole
WorkspaceRole
User’s actual role (if access granted)

Account Settings

Update user account settings.

Update Username

import { updateUsername } from '@/app/actions/workspace';

const result = await updateUsername('johndoe');

if (result.success) {
  console.log('Username updated');
}
Validation:
  • Minimum 3 characters
  • Maximum 255 characters
  • Only letters, numbers, underscores, and hyphens
  • Must be unique
const schema = z.string()
  .min(3, "Username must be at least 3 characters")
  .max(255)
  .regex(
    /^[a-zA-Z0-9_-]+$/,
    "Username can only contain letters, numbers, underscores, and hyphens"
  );

Change Email

Update user email address.
import { changeEmail } from '@/app/actions/workspace';

const result = await changeEmail(
  '[email protected]',
  '2fa_token' // Required if 2FA enabled
);

if (result.success) {
  console.log('Email updated - verification required');
}
Email Verification Required: After changing email, the account is marked as unverified. User must verify the new email address.
Security:
  • Requires 2FA verification if enabled
  • New email must not be in use
  • Email is normalized (trimmed, lowercased)

Change Password

Update user password.
import { changePassword } from '@/app/actions/workspace';

const result = await changePassword(
  'currentPassword123',
  'newSecurePassword456',
  '2fa_token' // Required if 2FA enabled
);

if (result.success) {
  console.log('Password changed successfully');
}
Validation:
  • Current password must be correct
  • New password must meet strength requirements
  • Requires 2FA if enabled
  • Not available for OAuth-only accounts
if (!currentPasswordHash) {
  return { error: "Password change not available for OAuth accounts" };
}

Delete Account

Permanently delete user account.
import { deleteUserAccount } from '@/app/actions/workspace';

const result = await deleteUserAccount(
  'delete my account', // Must type exactly
  '2fa_token' // Required if 2FA enabled
);

if (result.success) {
  // User deleted, redirected to sign-in
}

Deletion Requirements

1

Confirmation

User must type exactly “DELETE MY ACCOUNT” to confirm.
2

2FA Verification

If 2FA is enabled, valid token required.
3

Workspace Check

User must not own any workspaces:
const ownedWorkspaces = await db.query.workspace.findMany({
  where: eq(tables.workspace.user_id, user.id)
});

if (ownedWorkspaces.length > 0) {
  return { error: "Must transfer or delete workspaces first" };
}
4

Data Cleanup

System deletes:
  • All workspace memberships
  • All user sessions
  • User account record
Irreversible Action: Account deletion cannot be undone. All data is permanently removed.

Sign Out

Sign out the current user.
import { signOut } from '@/app/actions/auth';

const result = await signOut();

if (result.success) {
  // Session invalidated
  // Redirect to home page
}
Sign out process:
  1. Invalidates current session in database
  2. Deletes session cookie
  3. User is logged out
await invalidateSession(session.id);
await deleteSessionTokenCookie();

User Schema

The complete user object structure:
interface User {
  id: string;
  email: string;
  username: string | null;
  avatar: string | null;
  platform_role: PlatformRole | null;
  email_verified: boolean;
  registered_2fa: boolean;
  created_at: Date;
  updated_at: Date;
}

enum PlatformRole {
  ORGANIZER = "organizer",
  ATTENDEE = "attendee"
}

OAuth Accounts

Check if user has OAuth authentication.
import { checkUserHasOAuth } from '@/app/actions/workspace';

const result = await checkUserHasOAuth(userId);

if (result.hasOAuth) {
  console.log(`User signed in via ${result.provider}`);
  // Some features may not be available (e.g., password change)
}
OAuth Providers:
  • Google
  • GitHub
  • (More providers coming soon)
Password Management: Users who sign in exclusively via OAuth cannot change their password through the API.

2FA Verification

Sensitive operations require 2FA verification when enabled:
if (user.registered_2fa) {
  if (!verificationToken) {
    return { error: "2FA verification required", requires2FA: true };
  }
  
  const { verify2FAToken } = await import(
    '@/lib/server/two-factor-verification'
  );
  
  const verification = await verify2FAToken(verificationToken);
  
  if (!verification.valid) {
    return { error: "2FA verification failed" };
  }
}
Operations requiring 2FA:
  • Change email
  • Change password
  • Transfer workspace ownership
  • Delete workspace
  • Delete account

Error Handling

Common user API errors:
ErrorCauseSolution
"Authentication required"User not signed inCall requireAuth() or sign in
"Username is already taken"Duplicate usernameChoose different username
"Email is already in use"Duplicate emailUse different email
"Current password is incorrect"Wrong password providedVerify current password
"2FA verification required"2FA enabled but no tokenProvide valid 2FA token
"Password change not available for OAuth accounts"OAuth-only accountCannot set password
"Must transfer or delete workspaces first"User owns workspacesTransfer or delete workspaces

Complete Example

Complete user profile management:
import { 
  requireAuth,
  updateUsername,
  changeEmail,
  getUserWorkspaces
} from '@/app/actions/auth';
import { WorkspaceRole } from '@/lib/db/schema/enums';

async function updateUserProfile() {
  // 1. Ensure user is authenticated
  const { user } = await requireAuth();
  
  console.log('Current user:', user.email);
  
  // 2. Update username
  const usernameResult = await updateUsername('johndoe2024');
  
  if (!usernameResult.success) {
    console.error('Username update failed:', usernameResult.error);
    return;
  }
  
  console.log('Username updated');
  
  // 3. Update email (requires 2FA if enabled)
  let emailResult;
  
  if (user.registered_2fa) {
    // Prompt user for 2FA token
    const token = await prompt2FA();
    emailResult = await changeEmail('[email protected]', token);
  } else {
    emailResult = await changeEmail('[email protected]');
  }
  
  if (!emailResult.success) {
    console.error('Email update failed:', emailResult.error);
    return;
  }
  
  console.log('Email updated - please verify new email');
  
  // 4. Get user workspaces
  const workspaces = await getUserWorkspaces(user.id);
  
  console.log('User workspaces:');
  workspaces.forEach(({ workspace, role, isOwner }) => {
    console.log(
      `- ${workspace.name}: ${role}${isOwner ? ' (Owner)' : ''}`
    );
  });
  
  console.log('Profile update complete');
}

Next Steps

Workspaces API

Manage workspace memberships

Authentication

Learn about auth features

Authentication

Learn about authentication and 2FA

Events API

Create and manage events

Build docs developers (and LLMs) love