Created
August 9, 2023 15:09
-
-
Save umutyerebakmaz/43f0555aa1865f4e7753fcec16650ff1 to your computer and use it in GitHub Desktop.
Auth Interceptor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@angular/core'; | |
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; | |
import { Observable, BehaviorSubject } from 'rxjs'; | |
import { catchError, filter, switchMap, take } from 'rxjs/operators'; | |
import { AuthService } from '@services/auth.service'; | |
import { Router } from '@angular/router'; | |
import { TokenType } from '@app/graphql.module'; | |
@Injectable() | |
export class AuthInterceptor implements HttpInterceptor { | |
private isRefreshing = false; | |
private newAccessTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null); | |
constructor(private authService: AuthService, private router: Router) {} | |
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | |
const accessToken = this.authService.getAccessToken(); | |
if (accessToken === null) { | |
request = request.clone({ | |
setHeaders: { | |
Accept: 'charset=utf-8', | |
}, | |
}); | |
} | |
if (accessToken) { | |
request = this.setRequest(request, accessToken, 'access'); | |
} | |
return next.handle(request).pipe( | |
catchError((error: HttpErrorResponse) => { | |
const e = error.error.errors[0]; | |
if (e.message === 'expired token') { | |
if (!this.isRefreshing) { | |
this.isRefreshing = true; | |
this.newAccessTokenSubject.next(null); | |
const refreshToken = this.authService.getRefreshToken(); | |
return this.authService.refreshAccessToken(refreshToken).pipe( | |
switchMap(res => { | |
this.isRefreshing = false; | |
this.newAccessTokenSubject.next(res.accessToken); | |
const clonedRequest = this.setRequest(request, res?.accessToken, 'refresh'); | |
console.log(clonedRequest); | |
return next.handle(clonedRequest).pipe(); | |
}), | |
catchError(refreshError => { | |
this.isRefreshing = false; | |
this.authService.removeTokens(); | |
this.router.navigate(['login']); | |
throw new Error(refreshError); | |
}) | |
); | |
} else { | |
return this.newAccessTokenSubject.pipe( | |
filter(token => token !== null), | |
take(1), | |
switchMap(subject => { | |
console.log(4, subject); | |
const cloneRequest2 = this.setRequest(request, subject.accessToken, 'access'); | |
return next.handle(cloneRequest2); | |
}) | |
); | |
} | |
} | |
throw new Error(error as any); | |
}) | |
); | |
} | |
private setRequest(request: HttpRequest<any>, token: string, tokenType: TokenType): HttpRequest<any> { | |
return request.clone({ | |
setHeaders: { | |
Accept: 'charset=utf-8', | |
Authorization: `Bearer ${token}`, | |
tokenType: tokenType, | |
}, | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@aliosmanyuksel Hello, I tested and the result did not change. By default, the interceptor goes as access token and tokenType = 'access' in the header, and if this request gives an error as expired token from the server, it should treat the refreshToken endpoint as refresh token and tokenType = 'refresh'. In the current situation, the mutable is behaving correctly or there is something wrong with my setup.