Ionic with JWT authentication

I’m building an ionic 2 app and backend is powered by Nodejs Express app which issue jwt token to access protected api points. Currently I manage to implement login and store token using ionic storage. I need to inform user when token expired and and way to auto inject authentication header with token.

Any good implementation to look in to?

authHttp will send tokens with every request and jwtHelper has methods where you can check if a token is expired and do whatever.

I’m using it however I’m having some trouble with using ionic2 storage right now. I keep getting a token.split() error I believe its because when you use storage.set it saves the token as a JSON object.

I would say that your server must return a 401 when your token expired and then you must redirect customer to connection page.

My server is returning 401 but I need a centralized way to handle it and redirect to login. Currently I’m checking token expired using angular2-jwt in page constructors and It’s giving me unexpected results like when I first load the app it says token expired.

Ah ok sorry.
What I did, I created a common http service (which contains get, put, delete and post). It is used to make all call to my server
Then it catch errors status (like 401 or 404 etc) and create a dedicated error for error status (let’s say StatusError).
Once the status error is thrown you can either from all your service which call your http service put a catch and create an error handler which will do the rerooting for you.
Or create an ErrorHandler which override IonicErrorHandler and do the rerooting. However I don’t like this solution because for me this should be used for unexpected issues.

Can you please add sample code it would be good. Or link to good comprehensive tutorial also fine.

Here’s one approach.

1 Like

Hello,

Sorry for the delay.

I don’t know if it is the best approach but I like to be as closer as possible of my errors and to centralise call (and as I said IonicErrorHandler is for unexpected issue so error must not go as far as this)

The status error:

export class StatusError extends Error{

	constructor(private status : status){
		super();
	}
	
	isUnautorized() : boolean{
		return status == 401;
	}

}

The error handler

@Injectable
export class ErrorHandler{

	constructor(private navController : NavController,
				// the logout service is in charge of cleaning the DB (profiles, token etc)
				private logoutService : LogoutService){
	}
	
	handleError(err : Error){
		if(err instanceof StatusError){
			var statusError = <StatusError>err;
			if(statusError.isUnautorized()){
				this.logoutService.logout().then(() => this.navController.push(ConnectionPage))
			}
		}
		else{
			// rethrow error to handle it with IoniceErrorHandler
			throw err;
		}
	}
}

The httpService

@Injectable
export class HttpService {


	constructor(private http : Http){
	}
	
	post<RQ, RS>(urlComplement, content : RQ) : Promise<RS>{
	
		// here build your header
		return this.http.post("httpAddress" + urlComplement, content, {headers : header})
			.map((data) => data.json)
			// not mandatory but I like to work with promise
			.toPromise()
			.catch((error) => {
			  console.log("Unable to call httpAddress" + urlComplement + " because of " + error);
			  return Promise.reject(new StatusError(err.status))
			})
			.then((datajson) =>{
				
				var result = <RS>datajson;
				
				// do some check (for example functional checks (like functional errors from your api)


				return Promise.resolve(result)
			})
	}
	
	// do the same for get put and delete
}

Your component

@Component({
  selector: 'my-component',
  templateUrl: 'my-component.html',
})
export class MyComponent(){

	profile : Profile;

	constructor(private httpService : HttpService, private errorHandler : ErrorHandler){
	}
	
	updateProfile(){
		// this is an example of a service to update a profile
		this.httpService.post<ProfileRQ, ProfileRS>("/profile", new ProfileRQ(this.profile))
		.then(response => {
			// do something on the response
		}).catch(err => this.errorHandler.handleError(err))
	}

}