How to implement role-based auth in Angular

Role-based authentication (RBAC) allows you to control access to routes and features based on user roles. As the creator of CoreUI, I’ve implemented enterprise-grade authentication systems for Angular applications serving millions of users.

The most maintainable approach combines an auth service, route guards, and structural directives to enforce role-based access control throughout your application.

Create Auth Service

First, create a service to manage authentication and roles:

ng generate service services/auth

In src/app/services/auth.service.ts:

import { Injectable } from '@angular/core'
import { BehaviorSubject, Observable } from 'rxjs'
import { map } from 'rxjs/operators'

export interface User {
  id: string
  username: string
  email: string
  roles: string[]
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private currentUserSubject: BehaviorSubject<User | null>
  public currentUser: Observable<User | null>

  constructor() {
    const storedUser = localStorage.getItem('currentUser')
    this.currentUserSubject = new BehaviorSubject<User | null>(
      storedUser ? JSON.parse(storedUser) : null
    )
    this.currentUser = this.currentUserSubject.asObservable()
  }

  public get currentUserValue(): User | null {
    return this.currentUserSubject.value
  }

  login(username: string, password: string): Observable<User> {
    // Replace with actual HTTP call
    return new Observable(observer => {
      const user: User = {
        id: '1',
        username,
        email: `${username}@example.com`,
        roles: ['admin', 'user']
      }
      localStorage.setItem('currentUser', JSON.stringify(user))
      this.currentUserSubject.next(user)
      observer.next(user)
      observer.complete()
    })
  }

  logout(): void {
    localStorage.removeItem('currentUser')
    this.currentUserSubject.next(null)
  }

  hasRole(role: string): boolean {
    const user = this.currentUserValue
    return user ? user.roles.includes(role) : false
  }

  hasAnyRole(roles: string[]): boolean {
    const user = this.currentUserValue
    return user ? roles.some(role => user.roles.includes(role)) : false
  }

  hasAllRoles(roles: string[]): boolean {
    const user = this.currentUserValue
    return user ? roles.every(role => user.roles.includes(role)) : false
  }
}

Create Role Guard

Generate a guard to protect routes:

ng generate guard guards/role

In src/app/guards/role.guard.ts:

import { Injectable } from '@angular/core'
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'
import { AuthService } from '../services/auth.service'

@Injectable({
  providedIn: 'root'
})
export class RoleGuard implements CanActivate {
  constructor(
    private router: Router,
    private authService: AuthService
  ) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const currentUser = this.authService.currentUserValue

    if (currentUser) {
      const requiredRoles = route.data['roles'] as string[]

      if (requiredRoles && requiredRoles.length > 0) {
        if (this.authService.hasAnyRole(requiredRoles)) {
          return true
        }

        this.router.navigate(['/unauthorized'])
        return false
      }

      return true
    }

    this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } })
    return false
  }
}

Configure Routes with Roles

In your routing module:

import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { RoleGuard } from './guards/role.guard'

const routes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [RoleGuard],
    data: { roles: ['admin'] }
  },
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [RoleGuard],
    data: { roles: ['admin', 'user'] }
  },
  {
    path: 'profile',
    component: ProfileComponent,
    canActivate: [RoleGuard],
    data: { roles: ['user'] }
  },
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: 'unauthorized',
    component: UnauthorizedComponent
  }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

Create Role Directive

For conditional rendering based on roles:

ng generate directive directives/has-role

In src/app/directives/has-role.directive.ts:

import { Directive, Input, TemplateRef, ViewContainerRef, OnInit } from '@angular/core'
import { AuthService } from '../services/auth.service'

@Directive({
  selector: '[appHasRole]'
})
export class HasRoleDirective implements OnInit {
  private roles: string[] = []

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private authService: AuthService
  ) {}

  @Input()
  set appHasRole(roles: string | string[]) {
    this.roles = Array.isArray(roles) ? roles : [roles]
    this.updateView()
  }

  ngOnInit(): void {
    this.authService.currentUser.subscribe(() => {
      this.updateView()
    })
  }

  private updateView(): void {
    this.viewContainer.clear()

    if (this.authService.hasAnyRole(this.roles)) {
      this.viewContainer.createEmbeddedView(this.templateRef)
    }
  }
}

Use in Templates

<!-- Show for admins only -->
<button *appHasRole="'admin'" (click)="deleteUser()">
  Delete User
</button>

<!-- Show for admin or moderator -->
<div *appHasRole="['admin', 'moderator']">
  <h3>Moderation Panel</h3>
</div>

<!-- Show for all authenticated users -->
<nav *appHasRole="['admin', 'user', 'guest']">
  <a routerLink="/dashboard">Dashboard</a>
</nav>

Best Practice Note

This is the same role-based authentication architecture we use in CoreUI’s Angular admin templates. It provides fine-grained control over routes and UI elements while maintaining clean separation of concerns.

For production applications, consider using CoreUI’s Angular Admin Template which includes pre-built authentication, role-based access control, and integration with popular auth providers like Auth0 and Firebase. The template also includes ready-to-use components like Modal for login dialogs, Toast for auth notifications, and Sidebar with role-based visibility.

If you’re building authentication systems, you might also want to learn how to fetch data in Angular with HttpClient to connect your auth service to a backend API.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team