Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

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