this.storage.get(‘refresh_token’).then( ) returns a promise so it is returning a promise object instead of the token
I am working on a ionic 4 angular project where I am using jwt for authentication. Using the http interceptor I was able to send the access token as the authorization headers bearer token. Because jwt expires very quickly so now I need to refresh the token. I am using a python and flask backend where after successful login the server response contains both the access i.e. jwt and refresh token. In my python server to the refresh the token I need to do a post request to the refresh end point with the refresh token as as the authorization headers bearer token. In response the server send me the access token.
The steps that I have followed is :
- After successful log in I am saving the access token and the refresh token in the ionic storage.
- Sending the access token with each request using the angular http interceptor.
- If there is an error the server response with the appropriate error response code then I was sending a refresh token request adding the refresh token as the bearer token authorization header
- Then from the server response saving the access token in the ionic storage again
- Adding the new access token with each request.
Now the problem that I am facing is when I send the refresh token request instead of sending the refresh token as the authorization header the request is sending a “Bearer [object Promise]”.
The problem is in my authservice and getAccessTokenUsingRefreshToken( ) function which returns an observable.
as this.storage.get(‘refresh_token’).then( ) returns a promise so it is returning a promise object instead of the token.
The code of my authservice is as follows:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse, HttpRequest } from '@angular/common/http';
import { BehaviorSubject, throwError, Observable, from } from 'rxjs';
import { Platform, AlertController } from '@ionic/angular';
import { Storage } from '@ionic/storage';
import { JwtHelperService } from '@auth0/angular-jwt';
import { tap, catchError, mergeMap } from 'rxjs/operators';
import { User } from '../models/user.model';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(
private http: HttpClient,
private helper: JwtHelperService,
private storage: Storage,
private platform: Platform,
private alertController: AlertController) {
// this.platform.ready().then(() => {
// this.checkToken();
// });
}
url = 'http://localhost:5000';
ACCESS_TOKEN = 'access_token';
REFRESH_TOKEN = 'refresh_token';
user = null;
token;
// refreshToken;
authenticationState = new BehaviorSubject(false);
register(user: User): Observable<User> {
// if (user.id === null)
console.log(user);
return this.http.post<User>(`${this.url}/register`, user)
.pipe(
tap(res => {
this.storage.set(this.ACCESS_TOKEN, res[this.ACCESS_TOKEN]);
this.storage.set(this.REFRESH_TOKEN, res[this.REFRESH_TOKEN]);
this.user = this.helper.decodeToken(res[this.ACCESS_TOKEN]);
// console.log(this.storage.get(this.REFRESH_TOKEN));
this.authenticationState.next(true);
}),
);
}
login(data) {
return this.http.post(`${this.url}/auth`, data)
.pipe(
tap(res => {
this.storage.set(this.ACCESS_TOKEN, res[this.ACCESS_TOKEN]);
this.storage.set(this.REFRESH_TOKEN, res[this.REFRESH_TOKEN]);
this.user = this.helper.decodeToken(res[this.ACCESS_TOKEN]);
// this.storage.get(this.REFRESH_TOKEN);
// console.log(this.storage.get(this.ACCESS_TOKEN));
// console.log(this.getRefreshToken());
this.authenticationState.next(true);
}),
);
}
logout() {
this.storage.remove(this.ACCESS_TOKEN).then(() => {
this.authenticationState.next(false);
});
this.storage.remove(this.REFRESH_TOKEN);
}
private addToken(token: any) {
if (token) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
})
};
return httpOptions;
}
}
getAccessTokenUsingRefreshToken() {
const refreshToken = this.storage.get('refresh_token').then((result) => {
return result;
});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Bearer ${refreshToken}`
})
};
return this.http.post<any>(`${this.url}/token/refresh`, 'body', httpOptions ).pipe(tap(tokens => {
console.log(tokens['access_token']);
console.log(tokens);
this.storage.set(this.ACCESS_TOKEN, tokens[this.ACCESS_TOKEN]);
console.log(this.storage.get('access_token'));
}));
}
checkToken(): Promise<any> {
return this.storage.get(this.ACCESS_TOKEN).then(token => {
if (token) {
this.token = token;
if (!this.helper.isTokenExpired(this.token)) {
this.user = this.helper.decodeToken(this.token);
this.authenticationState.next(true);
} else {
this.storage.remove(this.ACCESS_TOKEN);
this.storage.remove(this.REFRESH_TOKEN);
}
}
});
}
getToken() {
return this.storage.get(this.ACCESS_TOKEN);
}
isAuthenticated() {
return this.authenticationState.value;
}
}
This is my http interceptor code
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, from, throwError, BehaviorSubject } from 'rxjs';
import { Storage } from '@ionic/storage';
// import { _throw } from 'rxjs/observable/throw';
import { catchError, mergeMap, switchMap, filter, take } from 'rxjs/operators';
import { AlertController } from '@ionic/angular';
import { AuthenticationService } from './authentication.service';
@Injectable({
providedIn: 'root'
})
export class InterceptorService implements HttpInterceptor {
private isRefreshing = false;
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(private storage: Storage, private alertCtrl: AlertController, private authenticationService: AuthenticationService) { }
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
let promise = this.storage.get('access_token');
return from(promise).pipe(mergeMap(token => {
const clonedReq = this.addToken(req, token);
return next.handle(clonedReq).pipe(catchError(error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
// console.log('executed');
console.log(req);
return this.handle401Error(req, next);
} else {
return throwError(error.message);
}
})
);
}
));
}
// Adds the token to your headers if it exists
private addToken(request: HttpRequest<any>, token: any) {
if (token) {
let clone: HttpRequest<any>;
clone = request.clone({
setHeaders: {
Accept: `application/json`,
'Content-Type': `application/json`,
Authorization: `Bearer ${token}`
}
});
return clone;
}
return request;
}
private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshing) {
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authenticationService.getAccessTokenUsingRefreshToken().pipe(
switchMap((token: any) => {
this.isRefreshing = false;
console.log(token);
console.log('executed');
this.refreshTokenSubject.next(token.access_token);
return next.handle(this.addToken(request, token.access_token));
}));
} else {
return this.refreshTokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(access_token => {
return next.handle(this.addToken(request, access_token));
}));
}
}
}