Skip to main content
BarberApp uses Firebase Authentication to securely manage user sessions and provide role-based access to different parts of the application.

Authentication flow

The authentication system is managed by the AuthFacade service, which provides a reactive state management layer using Angular signals.
1

User submits credentials

Users enter their email and password through the login or registration form.
2

Firebase Authentication

Credentials are validated against Firebase Authentication service.
3

User data retrieval

After successful authentication, user data is fetched from Firestore.
4

Role-based redirect

Users are automatically redirected to their appropriate dashboard based on their role.

Login

The login process is handled through the AuthFacade service:
auth.facade.ts:73-94
async login(email: string, password: string): Promise<void> {
  this._loading.set(true);
  this._error.set(null);

  try {
    await this.authService.login(email, password);
    const user = await this.authService.getCurrentUser();
    this._user.set(user);

    // Redirect user to appropriate dashboard based on role
    if (user) {
      this.redirectUserByRole(user);
    }
  } catch (error: any) {
    const errorMessage = this.getLoginErrorMessage(error);
    this._error.set(errorMessage || 'Error del servidor. Intenta más tarde.');
    this._user.set(null);
  } finally {
    this._loading.set(false);
    this.consoleInform();
  }
}

Login form component

The LoginFormComponent provides a reactive form with email and password validation:
login-form.component.ts:56-62
private createForm(): FormGroup {
  return this.fb.group({
    email: ['', [Validators.required, Validators.email]],
    password: ['', Validators.required],
    showPassword: new FormControl(false),
  });
}

Error handling

Firebase authentication errors are mapped to user-friendly messages:
auth.facade.ts:142-160
private getLoginErrorMessage(error: any): string {
  const code = error?.code;

  switch (code) {
    case 'auth/user-not-found':
    case 'auth/wrong-password':
    case 'auth/invalid-credential':
      return 'Correo o contraseña incorrectos.';

    case 'auth/too-many-requests':
      return 'Demasiados intentos fallidos. Intenta más tarde.';

    case 'auth/invalid-email':
      return 'Correo electrónico inválido.';

    default:
      return 'Error al iniciar sesión. Intenta nuevamente.';
  }
}

Registration

New users can register as either clients or specialists. The registration process involves multiple steps:
1

Choose user type

Select between Client or Specialist role
2

Fill in basic information

Provide firstName, lastName, DNI, sex, birthDate, email, and password
3

Add role-specific data

  • Clients: Height and weight (optional)
  • Specialists: Specialties and availability schedule (required)
4

Upload profile picture

Optional profile picture upload via Cloudinary
5

Submit registration

Account is created in Firebase Auth and user data is stored in Firestore

Registration implementation

auth.facade.ts:102-116
async register(email: string, password: string): Promise<string | void> {
  this._loading.set(true);
  this._error.set(null);

  try {
    const uid = await this.authService.register(email, password);
    return uid;
  } catch (error: any) {
    const errorMessage = this.getRegisterErrorMessage(error);
    this._error.set(errorMessage || 'Error del servidor. Intenta más tarde.');
  } finally {
    this._loading.set(false);
    this.consoleInform();
  }
}
The registration form validates DNI uniqueness before creating the Firebase account to prevent duplicate users.

Role-based redirect

After successful authentication, users are automatically redirected based on their role:
auth.facade.ts:186-203
redirectUserByRole(user: UserBase): void {
  switch (user.role) {
    case UserRoles.CLIENT:
      this.router.navigate(['/dashboard/client']);
      break;
    case UserRoles.SPECIALIST:
      this.router.navigate(['/dashboard/specialist']);
      break;
    case UserRoles.ADMIN:
      this.router.navigate(['/dashboard/specialist']);
      break;
    default:
      // Default fallback
      console.warn('Unknown user role:', user.role);
      this.router.navigate(['/dashboard/client']);
      break;
  }
}

Authentication state

The AuthFacade exposes reactive signals for authentication state:
auth.facade.ts:18-29
private _user = signal<UserBase | null>(null);
private _loading = signal<boolean>(false);
private _checkingAuth = signal<boolean>(false);
private _error = signal<string | null>(null);

// Public signals to interact with the auth service
readonly user = this._user.asReadonly();
readonly isAuthenticated = computed(() => !!this._user());
readonly isLoading = this._loading.asReadonly();
readonly isCheckingAuth = this._checkingAuth.asReadonly();
readonly error = this._error.asReadonly();

Checking authentication status

auth.facade.ts:45-65
async checkAuthStatus(): Promise<void> {
  this._checkingAuth.set(true);
  console.log('Check Auth Status Started');

  try {
    const isAuthenticated = await this.authService.isAuthenticated();
    console.log(isAuthenticated)
    if (isAuthenticated) {
      const currentUser = await this.authService.getCurrentUser();
      this._user.set(currentUser);
    } else {
      this._user.set(null);
    }
  } catch (error: any) {
    this._user.set(null);
    this._error.set(error.message || 'Error checking authentication status');
  } finally {
    this._checkingAuth.set(false);
    this.consoleInform();
  }
}

Logout

Users can log out at any time, which clears the authentication state:
auth.facade.ts:122-135
async logout(): Promise<void> {
  this._loading.set(true);
  this._error.set(null);

  try {
    await this.authService.logout();
    this._user.set(null);
  } catch (error: any) {
    this._error.set(error.message || 'Logout failed');
  } finally {
    this._loading.set(false);
    this.consoleInform();
  }
}

Route protection

BarberApp uses Angular route guards to protect authenticated routes. See the User Roles documentation for details on role-based access control.
Always validate user authentication status on both the client and server side for security.

Build docs developers (and LLMs) love