feat: delete users - not tested

This commit is contained in:
Eric Gullickson
2025-12-22 18:20:25 -06:00
parent 91b4534e76
commit 4897f0a52c
73 changed files with 4923 additions and 62 deletions

View File

@@ -0,0 +1,200 @@
/**
* Auth0 Management API Client
* Provides methods for user management operations via Auth0 Management API
*/
import { ManagementClient } from 'auth0';
import { appConfig } from '../config/config-loader';
import { logger } from '../logging/logger';
interface CreateUserParams {
email: string;
password: string;
}
interface UserDetails {
userId: string;
email: string;
emailVerified: boolean;
}
class Auth0ManagementClientSingleton {
private client: ManagementClient | null = null;
private readonly CONNECTION_NAME = 'Username-Password-Authentication';
/**
* Lazy initialization of ManagementClient to avoid startup issues
*/
private getClient(): ManagementClient {
if (!this.client) {
const config = appConfig.getAuth0ManagementConfig();
this.client = new ManagementClient({
domain: config.domain,
clientId: config.clientId,
clientSecret: config.clientSecret,
});
logger.info('Auth0 Management API client initialized');
}
return this.client;
}
/**
* Create a new user in Auth0
* @param email User's email address
* @param password User's password
* @returns Auth0 user ID
*/
async createUser({ email, password }: CreateUserParams): Promise<string> {
try {
const client = this.getClient();
const response = await client.users.create({
connection: this.CONNECTION_NAME,
email,
password,
email_verified: false,
});
const user = response.data;
if (!user.user_id) {
throw new Error('Auth0 did not return a user_id');
}
logger.info('User created in Auth0', { userId: user.user_id, email });
return user.user_id;
} catch (error) {
logger.error('Failed to create user in Auth0', { email, error });
throw new Error(`Auth0 user creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get user details from Auth0
* @param userId Auth0 user ID (format: auth0|xxx or google-oauth2|xxx)
* @returns User details including email and verification status
*/
async getUser(userId: string): Promise<UserDetails> {
try {
const client = this.getClient();
const response = await client.users.get({ id: userId });
const user = response.data;
if (!user.email) {
throw new Error('User email not found in Auth0 response');
}
logger.info('Retrieved user from Auth0', { userId, email: user.email });
return {
userId: user.user_id || userId,
email: user.email,
emailVerified: user.email_verified || false,
};
} catch (error) {
logger.error('Failed to get user from Auth0', { userId, error });
throw new Error(`Auth0 user retrieval failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Resend email verification to user
* @param userId Auth0 user ID
*/
async resendVerificationEmail(userId: string): Promise<void> {
try {
const client = this.getClient();
await client.jobs.verifyEmail({
user_id: userId,
});
logger.info('Verification email sent', { userId });
} catch (error) {
logger.error('Failed to send verification email', { userId, error });
throw new Error(`Failed to send verification email: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Check if user's email is verified
* @param userId Auth0 user ID
* @returns true if email is verified, false otherwise
*/
async checkEmailVerified(userId: string): Promise<boolean> {
try {
const user = await this.getUser(userId);
return user.emailVerified;
} catch (error) {
logger.error('Failed to check email verification status', { userId, error });
throw new Error(`Failed to check email verification: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Delete a user from Auth0 (permanent deletion)
* @param userId Auth0 user ID (format: auth0|xxx or google-oauth2|xxx)
*/
async deleteUser(userId: string): Promise<void> {
try {
const client = this.getClient();
await client.users.delete({ id: userId });
logger.info('User deleted from Auth0', { userId });
} catch (error) {
logger.error('Failed to delete user from Auth0', { userId, error });
throw new Error(`Auth0 user deletion failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Verify user password using Resource Owner Password Grant
* @param email User's email address
* @param password User's password to verify
* @returns true if password is valid, false otherwise
*/
async verifyPassword(email: string, password: string): Promise<boolean> {
try {
const config = appConfig.getAuth0ManagementConfig();
const response = await fetch(`https://${config.domain}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
grant_type: 'password',
username: email,
password,
client_id: config.clientId,
client_secret: config.clientSecret,
audience: `https://${config.domain}/api/v2/`,
scope: 'openid profile email',
}),
});
if (response.ok) {
logger.info('Password verification successful', { email });
return true;
}
if (response.status === 403 || response.status === 401) {
logger.info('Password verification failed - invalid credentials', { email });
return false;
}
const errorBody = await response.text();
logger.error('Password verification request failed', { email, status: response.status, error: errorBody });
throw new Error(`Password verification failed with status ${response.status}`);
} catch (error) {
logger.error('Failed to verify password', { email, error });
throw new Error(`Password verification failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
// Export singleton instance
export const auth0ManagementClient = new Auth0ManagementClientSingleton();