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.
Related Articles
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.



