feat(auth): add resend verification email to all login pages

Add ability to resend verification email when login fails with
"Email not verified" error. Implemented across all 14 apps using
Mana Core Auth.

Changes:
- Add POST /api/v1/auth/resend-verification endpoint to mana-core-auth
- Add resendVerificationEmail method to shared-auth client
- Update LoginPage component with resend UI and translations
- Add resendVerificationEmail to all app auth stores
- Add translations for de, en, fr, es, it
- Add PlantaLogo to shared-branding
- Migrate planta login to shared LoginPage component
This commit is contained in:
Till-JS 2026-01-29 14:55:49 +01:00
parent f911243bf0
commit 0c150df0f1
45 changed files with 691 additions and 110 deletions

View file

@ -20,6 +20,7 @@ import { AcceptInvitationDto } from './dto/accept-invitation.dto';
import { SetActiveOrganizationDto } from './dto/set-active-organization.dto';
import { ForgotPasswordDto } from './dto/forgot-password.dto';
import { ResetPasswordDto } from './dto/reset-password.dto';
import { ResendVerificationDto } from './dto/resend-verification.dto';
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
/**
@ -173,6 +174,21 @@ export class AuthController {
);
}
/**
* Resend verification email
*
* Sends a new verification email to the user.
* Always returns success to prevent email enumeration attacks.
*/
@Post('resend-verification')
@HttpCode(HttpStatus.OK)
async resendVerification(@Body() resendVerificationDto: ResendVerificationDto) {
return this.betterAuthService.resendVerificationEmail(
resendVerificationDto.email,
resendVerificationDto.sourceAppUrl
);
}
// =========================================================================
// B2B Registration
// =========================================================================

View file

@ -0,0 +1,10 @@
import { IsEmail, IsOptional, IsString } from 'class-validator';
export class ResendVerificationDto {
@IsEmail()
email: string;
@IsOptional()
@IsString()
sourceAppUrl?: string;
}

View file

@ -996,6 +996,49 @@ export class BetterAuthService {
}
}
/**
* Resend verification email
*
* Sends a new verification email to the user.
* Uses Better Auth's sendVerificationEmail API.
*
* @param email - User's email address
* @param sourceAppUrl - Optional URL to redirect after verification
* @returns Success status (always returns success to prevent email enumeration)
*/
async resendVerificationEmail(
email: string,
sourceAppUrl?: string
): Promise<{ success: boolean; message: string }> {
try {
// Store source app URL for email verification redirect
if (sourceAppUrl) {
sourceAppStore.set(email, sourceAppUrl);
}
// Better Auth's sendVerificationEmail method
// See: https://www.better-auth.com/docs/authentication/email-verification
const api = this.auth.api as any;
await api.sendVerificationEmail({
body: { email },
});
// Always return success to prevent email enumeration
return {
success: true,
message: 'If an account with that email exists, a verification email has been sent',
};
} catch (error) {
console.error('[resendVerificationEmail] Error:', error);
// Always return success to prevent email enumeration attacks
return {
success: true,
message: 'If an account with that email exists, a verification email has been sent',
};
}
}
/**
* Get JWKS (JSON Web Key Set)
*