Authentication and authorization are crucial aspects of an Angular application, where authentication verifies the identity of the user, and authorization handles what actions users are allowed to perform after being authenticated.
To implement authentication and authorization in an Angular application, you can use the following approach:
1. **Choose an authentication provider:**
The first step is to choose a reliable authentication provider such as:
- JSON Web Tokens (JWT)
- OAuth 2.0 / OpenID Connect
- Firebase auth
These providers offer different mechanisms to authenticate users with various types of tokens or other means, which you’ll use to make secure API calls and manage user access.
2. **Implement an authentication service:**
Create a centralized authentication service that is responsible for:
- Login and logout operations
- Storing the authentication tokens
- Refreshing tokens (if applicable)
Here’s an example of an authentication service using JWT:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
@Injectable()
export class AuthenticationService {
constructor(private http: HttpClient) { }
login(username: string, password: string) {
return this.http.post<any>('/api/authenticate', { username, password })
.pipe(map(user => {
if (user && user.token) {
localStorage.setItem('currentUser', JSON.stringify(user));
}
return user;
}));
}
logout() {
localStorage.removeItem('currentUser');
}
}
3. **Implement route guards for authorization:** Route guards in Angular are used to allow or prevent navigation to different routes based on certain conditions. Implement an ‘AuthGuard‘ that checks if the user is authenticated before allowing navigation to protected routes.
Here’s an example of an ‘AuthGuard‘:
import { Injectable } from '@angular/core';
import {
Router,
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from '@angular/router';
import { AuthenticationService } from './authentication.service';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authenticationService: AuthenticationService
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const currentUser = this.authenticationService.currentUserValue;
if (currentUser) {
// Authorized, so return true
return true;
}
// Not logged in, so redirect to login page with the return URL
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
4. **Configure protected routes and apply the guard:** Define protected routes in your application and apply the ‘AuthGuard‘ to them to ensure that only authenticated users can access them.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{ path: '', component: HomeComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
// Otherwise redirect to home
{ path: '**', redirectTo: '' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
5. **Intercept HTTP requests with token:** Use an HTTP interceptor to automatically attach the authentication token to all outgoing HTTP requests. This helps ensure that the server always receives the required authentication information.
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthenticationService } from './authentication.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const currentUser = this.authenticationService.currentUserValue;
if (currentUser && currentUser.token) {
// Clone the request and add the token header
request = request.clone({
setHeaders: { Authorization: `Bearer ${currentUser.token}` }
});
}
return next.handle(request);
}
}
6. **Handle unauthorized status and redirect if necessary:** In case the server returns an unauthorized (401) status, implement an error interceptor to handle the response and redirect the user to the login page when necessary.
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AuthenticationService } from './authentication.service';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(catchError(err => {
if (err instanceof HttpErrorResponse && err.status === 401) {
// Auto logout if 401 response is returned from the API
this.authenticationService.logout();
location.reload(true);
}
const error = err.error.message || err.statusText;
return throwError(error);
}));
}
}
After implementing these steps, your Angular application will have a robust authentication and authorization system in place. Users will be required to login to access protected pages, and their permissions will determine their level of access.