Ionic 4 Storage Token Access for HTTP Interceptor

Hey guys, doing a quick post here to spare another human the pain I just went through to get this working.

The problem:
Access the ionic storage. Get your token, modify the request headers and send the request.

Sounds easy but not quite. The problem is that the promise is asynchronous which means it does not care whether you have the token or not. It will send your request with most likely a null token as it does not wait. The async/wait approach did not work.

Below is my code which i modified for the ionic storage off a solution I saw somewhere for a similar Angular 7 problem. The important things to pay attention to here is the from and SwitchMap imports from rxjs.

Hope this helps!

Code:

import {Injectable} from '@angular/core';
import {
    HttpInterceptor,
    HttpRequest,
    HttpResponse,
    HttpHandler,
    HttpEvent,
    HttpErrorResponse
} from '@angular/common/http';

import { Observable, throwError, from } from 'rxjs';
import { map, catchError, switchMap } from 'rxjs/operators';

import { AlertController } from '@ionic/angular';
import { Storage } from '@ionic/storage';


const TOKEN_KEY = 'auth-token';

@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {

    protected url   = 'http://example.com/api';
    protected debug = true;

    constructor(private alertController: AlertController, private storage: Storage) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        // YOU CAN ALSO DO THIS
        // const token = this.authenticationService.getToke()

        return from(this.storage.get(TOKEN_KEY))
            .pipe(
                switchMap(token => {
                    if (token) {
                        request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });
                    }

                    if (!request.headers.has('Content-Type')) {
                        request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') });
                    }

                    if (this.debug) {
                        request = request.clone({ url: this.url + request.url + '?XDEBUG_SESSION_START=1'});
                    }

                    return next.handle(request).pipe(
                        map((event: HttpEvent<any>) => {
                            if (event instanceof HttpResponse) {
                                // do nothing for now
                            }
                            return event;
                        }),
                        catchError((error: HttpErrorResponse) => {
                            const status =  error.status;
                            const reason = error && error.error.reason ? error.error.reason : '';

                            this.presentAlert(status, reason);
                            return throwError(error);
                        })
                    );
                })
            );


    }

    async presentAlert(status, reason) {
        const alert = await this.alertController.create({
            header: status + ' Error',
            subHeader: 'Subtitle',
            message: reason,
            buttons: ['OK']
        });

        await alert.present();
    }
}

15 Likes

thanks, helps me a lot

Thanks a lot, this was really helpful.