Destino Dev

Blog

Autenticação reativa com Guards, Signals e Standalone Components em Angular (passo a passo)

Por John Pires · 16 de março de 2026

1) Por que aprender isso em 2026

Em 2026, aplicações web continuam exigindo UIs reativas, segurança nas rotas e arquiteturas componíveis. Angular evoluiu para tornar signals e standalone components peças centrais na construção de apps limpos e performáticos. Entender como integrar autenticação reativa com guards e signals evita lógica duplicada, facilita testes e reduz bugs de sincronização entre estado e UI.

Para iniciantes, a ideia central é simples: Signals mantêm estado reativo dentro do Angular sem depender exclusivamente de RxJS; Standalone Components removem a boilerplate de módulos; Guards protegem rotas com lógica executada pelo Router. Juntos, permitem um fluxo claro: serviço de autenticação (signal) → componente (consome o signal) → guard (decide acesso).

Neste artigo investigamos alternativas (RxJS, BehaviorSubject, NGRX) e escolhemos Signals por simplicidade para iniciantes, mantendo compatibilidade com RxJS quando necessário. Você verá por que essa combinação é mais robusta para apps pequenos e médios.

Resumo do problema: Como garantir que rotas estejam protegidas por um estado de autenticação que atualiza a UI de forma imediata, sem contestar a experiência do usuário e mantendo o código simples para quem está começando?

Alternativas e trade-offs

Podemos fazer autenticação com:

  • BehaviorSubject (RxJS): poderoso, mas adiciona complexidade de assinaturas e unsubscribe.

  • NGRX/Store: ótimo para apps grandes, mas complexo para iniciantes.

  • Signals (Angular): reatividade embutida, sintaxe direta e integração com templates.

Escolhemos Signals pela curva de aprendizado mais suave e pela integração direta com componentes standalone.

O que você vai aprender

Ao final terá um micro-projeto com:

  1. Serviço de autenticação com signals.

  2. Standalone components para Login, Home e Dashboard.

  3. Guard que protege a rota de Dashboard.

  4. Uso de Router com UrlTree para redirecionar não autenticados.

2) Configuração do ambiente

Comece com uma versão recente do Angular (16 ou superior é recomendável para signals e standalone). Tenha Node.js (>=18) e Angular CLI atualizados.

Passo a passo do setup

Crie um novo projeto Angular standalone:

npx @angular/cli@latest new auth-signals --standalone --routing --style=scss

O comando acima gera um projeto sem módulos NgModule (ou reduz a sua necessidade) e já cria o roteamento básico. Depois, entre na pasta e instale dependências básicas:

cd auth-signals
npm install

Abra o projeto no editor. Vamos adicionar arquivos para serviço de autenticação, guards e componentes standalone.

Estrutura de arquivos que usaremos

Criar os arquivos abaixo:

  • src/app/services/auth.service.ts

  • src/app/guards/auth.guard.ts

  • src/app/login/login.component.ts (standalone)

  • src/app/dashboard/dashboard.component.ts (standalone)

  • src/app/home/home.component.ts (standalone)

Essa estrutura é didática e permite entender responsabilidades: serviço cuida do estado, guard decide sobre rotas, componentes mostram UI.

3) Hello World progressivo

Vamos construir passo a passo. Primeiro, o serviço de autenticação usando signals. Ele vai expor um signal público para o usuário e métodos login/logout. O login será simulado para manter simples.

Serviço de autenticação com signals

O código abaixo cria um serviço Angular que usa signal para armazenar o usuário autenticado. Signals são funções reativas; chama-se a signal para ler o valor e pode-se usar set para atualizar.

/* src/app/services/auth.service.ts
   Serviço que mantém o estado de autenticação com signals.
   - user: signal que contém um objeto { id, name } ou null
   - login: simula autenticação assíncrona e atualiza a signal
   - logout: limpa a signal
*/

import { Injectable, signal } from '@angular/core';

export interface User { id: string; name: string }

@Injectable({ providedIn: 'root' })
export class AuthService {
  private _user = signal(null);
  // exposição somente leitura (padrão: chamando a função)
  user = () => this._user();

  login(name: string) {
    // Simula chamada de API com Promise
    return new Promise((resolve) => {
      setTimeout(() => {
        const u: User = { id: Date.now().toString(), name };
        this._user.set(u);
        resolve(u);
      }, 600); // simula latência
    });
  }

  logout() {
    this._user.set(null);
  }

  isAuthenticated(): boolean {
    return !!this._user();
  }
}

Após esse bloco, temos o estado centralizado. Qualquer componente pode injetar AuthService e usar auth.user() para ler o valor reativo.

Login component (standalone)

O LoginComponent usa o serviço para executar login. É um standalone component; não precisamos declarar em um módulo.

/* src/app/login/login.component.ts
   Componente standalone simples com template inline.
   - captura nome do usuário
   - chama auth.login
*/

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { CommonModule } from '@angular/common';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [CommonModule],
  template:
    Login 
    Entrar
    Autenticando...

})
export class LoginComponent {
  name = '';
  loading = false;
  constructor(private auth: AuthService, private router: Router) {}

  async doLogin() {
    this.loading = true;
    await this.auth.login(this.name || 'Usuário');
    this.loading = false;
    this.router.navigateByUrl('/dashboard');
  }
}

Depois de executar o login, navegamos para /dashboard. O guard da rota verificará a autenticidade.

4) Mini-projeto prático

Agora juntamos as peças: guard, rotas e componentes. O guard usará o AuthService com inject() para decisão. Também mostrarei como redirecionar com UrlTree quando não autenticado.

AuthGuard usando inject()

O guard é uma classe que implementa CanActivate. Ele injeta AuthService e Router via inject() para ser compatível com ambientes standalone e facilitar testes.

/* src/app/guards/auth.guard.ts
   Guard que protege rotas. Retorna true se autenticado
   ou um UrlTree apontando para /login para redirecionamento.
*/

import { Injectable, inject } from '@angular/core';
import { CanActivate, Router, UrlTree } from '@angular/router';
import { AuthService } from '../services/auth.service';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  canActivate(): boolean | UrlTree {
    const auth = inject(AuthService);
    const router = inject(Router);
    if (auth.isAuthenticated()) return true;
    return router.createUrlTree(['/login']);
  }
}

Se não autenticado, retornamos um UrlTree que instrui o Router a redirecionar para /login. Isso evita navegações desnecessárias.

Dashboard e Home (standalone)

Dashboard mostra o usuário corrente via signal e permite logout. Home é público.

/* src/app/dashboard/dashboard.component.ts
   Dashboard consome auth.user() diretamente para exibir dados.
*/

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [CommonModule],
  template: 
    Dashboard 
    Bem-vindo, {{ u.name }} (id: {{ u.id }}) 
    Estado inesperado: sem usuário 
    Sair
})
export class DashboardComponent {
  constructor(public auth: AuthService) {}
  user = this.auth.user; // signal exposta para template
  logout() {
    this.auth.logout();
  }
}

Note que o template usa a signal como função: user(). Essa chamada reativa atualiza o template automaticamente quando o valor muda.

Roteamento com guard

Defina rotas no arquivo principal (app.routes.ts ou direto em main.ts dependendo do setup). Aqui um exemplo claro:

/* src/app/app.routes.ts
   Rotas usando standalone components e guard
*/

import { Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { AuthGuard } from './guards/auth.guard';
import { Component } from '@angular/core';

export const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) },
  { path: 'login', component: LoginComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: '**', redirectTo: 'home' }
];

Com isso, qualquer tentativa de acessar /dashboard passará pelo AuthGuard. Se o usuário não estiver autenticado, será redirecionado para /login.

Erros comuns, armadilhas e dicas práticas

Nesta seção destaco problemas que iniciantes frequentemente encontram e como evitá-los.

Erro 1: esquecer de fornecer o serviço ou importar correto

Se esquecer de adicionar providedIn: 'root' ou importar arquivos, o Angular pode criar múltiplas instâncias do serviço. Certifique-se de usar providedIn ou declarar providers apenas quando necessário.

Erro 2: chamadas síncronas no guard esperando assíncrono

Se a verificação de autenticação depende de uma chamada HTTP, transforme o guard para retornar Observable/Promise ou resolva o estado antes do navigational guard. Não bloqueie a UI com await longo; prefira retornar um UrlTree padrão e depois autenticar com flows apropriados.

Dica: para autenticação real, armazene token em cookie/secure storage e inicialize o signal na criação do serviço checando esse storage.

5) Recursos para continuar estudando

Se quiser aprofundar em cada peça, estude os seguintes tópicos e links oficiais. Aprender o core de signals e Router ajuda a construir aplicações escaláveis.

Recursos oficiais

  • Documentação oficial Angular — seção Signals

  • Guia de Router — Guards e UrlTree

Práticas recomendadas

  1. Mantenha serviços puros: evite lógica de UI dentro deles.

  2. Use signals para estado local e combine com RxJS quando precisar mapear streams externos.

  3. Teste guards isoladamente injetando mocks de AuthService.

Conclusão prática

Signals + Guards + Standalone Components formam uma combinação eficiente para autenticação em Angular. Signals reduzem a complexidade das assinaturas RxJS para usos simples, standalone components tornam o projeto modular e Guards centralizam a decisão de acesso às rotas.

Próximos passos práticos:

  • Substitua o login simulado por uma chamada real a API e trate tokens com segurança.

  • Adicione um initialiser no serviço para restaurar sessão a partir do storage.

  • Implemente testes unitários para AuthService e AuthGuard.

O fluxo básico já implementado no mini-projeto serve como esqueleto para ampliar funcionalidades sem reescrever dependências centrais. Avance integrando Interceptor para adicionar token em requisições e usando effects/side-effects quando necessário.

Com esses conceitos consolidados você terá uma base sólida para construir aplicações reais e expandir para padrões mais avançados quando necessário.

Assuntos: Angular, signals, guards, standalone-components, routing, rxjs

Leia também