For your Angular application, setting up a robust API layer with JWT authentication involves a few key steps. Here’s an approach to structure the Angular services to cleanly separate concerns and ensure modularity: ### Approach: 1. **Interceptor Setup:** Implement an HTTP interceptor in Angular to automatically inject the JWT token into all outgoing requests. 2. **Service Layer:** Develop a service for each entity (auth, courses, modules, levels) to handle API calls. 3. **Handling Token Expiry:** Ensure the interceptor can handle token expiration by fetching a new token if necessary. ### Step 1: Setup JWT Interceptor The interceptor will attach the JWT token stored in localStorage or a similar client-side storage to each HTTP request. **File: /src/app/core/interceptors/auth.interceptor.ts** ```typescript import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError, switchMap } from 'rxjs/operators'; import { AuthService } from '../services/auth.service'; // Ensure AuthService has the logic to refresh tokens @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authService: AuthService) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token = localStorage.getItem('token'); // Get the token from storage if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request).pipe( catchError(error => { // Check if we received a 401 Unauthorized response if (error.status === 401) { return this.handle401Error(request, next); } return throwError(error); }) ); } private handle401Error(request: HttpRequest<any>, next: HttpHandler) { return this.authService.refreshToken().pipe( switchMap((token: any) => { localStorage.setItem('token', token); request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); return next.handle(request); }), catchError((err) => { this.authService.logout(); // Clear the token and logout if refresh fails return throwError(err); }) ); } } ``` ### Step 2: Setup Angular Services Create separate service files for different API functionalities. **File: /src/app/services/auth.service.ts** ```typescript import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { private apiUrl = 'http://localhost:3000/api/auth'; constructor(private http: HttpClient) {} login(credentials: { email: string, password: string }): Observable<any> { return this.http.post(`${this.apiUrl}/login`, credentials); } refreshToken(): Observable<any> { // Implement refresh token logic here, possibly calling an API endpoint return this.http.get(`${this.apiUrl}/refresh-token`); } logout() { localStorage.removeItem('token'); // Handle logout logic } } ``` **Repeat similar setups for other services like Courses, Modules, Levels, etc., ensuring each service is modular and handles only its relevant API calls.** ### Step 3: Register Interceptor Ensure your interceptor is registered in your Angular app module. **File: /src/app/app.module.ts** ```typescript import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthInterceptor } from './core/interceptors/auth.interceptor'; import { NgModule } from '@angular/core'; // Other imports @NgModule({ declarations: [ // Your components here ], imports: [ // other modules HttpClientModule ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { } ``` ### Conclusion: This setup ensures that your Angular frontend can handle JWT tokens efficiently, with each service being responsible for specific parts of the API. This architecture helps keep your application organized and maintainable. Let me know if this approach works for you or if you need further customization!