# Silent login when token expired?

**URL:** <https://forum.ionicframework.com/t/silent-login-when-token-expired/107127>\
**Category:** ionic-v3\
**Created:** [September 29, 2017, 11:09am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127 "2017-09-29T11:09:50Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [September 29, 2017, 11:09am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/1 "2017-09-29T11:09:50Z")

</div>

in the ionic way ? I use the below code but it does not work.

When I entered to homepage the log is not display as I want (In console log, it show : **first** then **last** , and the last is **second** ) so It always return token invalid because it does not run in order. I dont know where I wrong.  
Please help me. Thank you all !

```auto
  logIn(identifi : string, password : string ) {
    let headers = new Headers();
    headers.append('Access-Control-Allow-Origin', '*');
    headers.append('Access-Control-Allow-Methods', '*');
    headers.append('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');    
    let body = {
      "user_id" : identifi,
      "password" : password
    };
    let options = new RequestOptions({ headers: headers });
    return this.http.post(api.logIn, body, options).map((res:Response) => res.json());
  }  

  checkToken() {
    this.storage.get('user').then((user) => {
      if(user) {
        this.token = user.token;
        this.token_date = user.token_date - 100;
        this.currentDate = new Date();
        this.expDate = new Date(this.token_date * 1000);
        if (this.expDate === this.currentDate) {
          // token expired, login again     
          console.log('first');  
          this.logIn(user.user_id, user.password).subscribe(
            data => {
              this.storage.set("user", userInfo);  
              console.log('second');
              return userInfo.token;
            },
            err => {
              console.log(err);
            });
        }
      }
    })
  }

  getDataHomepage(retailerId: number,pageIndex: number) {
    this.checkToken();
    console.log('last');
    let headers = new Headers();
    headers.append('Authorization', 'Bearer ' + this.token);
    let options = new RequestOptions({ headers: headers });
    return this.http.get(api.promotion + '?retailer_id=' + retailerId + '&page=' + pageIndex, options).map((res:Response) => res.json());
  }

```

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [September 29, 2017, 11:36pm UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/2 "2017-09-29T23:36:04Z")

</div>

First off, CORS is a server-side thing. Lose all the `headers` junk in `login()`. Next, please read [this post](https://forum.ionicframework.com/t/ionic-app-loading-sequence/100109/11?u=rapropos).

Done? `checkToken()`, which should be renamed because that’s not what it does, needs to return `Observable<string>`, because it’s of type C in that linked post, as `getDataHomepage()` cares about how it resolves. Its first word should also be `return`. That is going to make you have to rethink how it’s structured (likely using `fromPromise` and `mergeMap`), but once that’s done, then there will be no `subscribe` in it, and the `subscribe` will move to `getDataHomepage` instead, in which you will have the needed value.

Incidentally, I would strongly recommend looking into the interceptor feature introduced in [the new HttpClient API](https://angular.io/guide/http), now that Ionic officially supports it. You can centralize all of your token management using it, so you won’t have to repeat all that boilerplate in other service provider methods.

Finally, storing passwords on device is extremely careless from a security perspective. Please stop doing that.

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 2, 2017, 3:19am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/3 "2017-10-02T03:19:15Z")

</div>

Thank @rapropos for your help. Can you give me a sample code for this ? I’m really don’t know how to do it ☹

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 2, 2017, 8:47am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/4 "2017-10-02T08:47:56Z")

</div>

Anyone help ? I’m still stuck ☹

---

<div class="post-metadata">

**Author:** ![jsanta](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/jsanta/32/66466_2.png) [@jsanta](https://forum.ionicframework.com/u/jsanta)\
**Post date:** [October 2, 2017, 10:21am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/5 "2017-10-02T10:21:14Z")

</div>

If you’re using JWT with a refreshtoken, you should check every HTTP call, if it returns an error code (let’s say Token expired) you have to use the refreshtoken to get a new one. Store it and use it while it lasts, then rinse and repeat if required.  
I have some HTTP interceptor code to share but I guess you’ll have to modify some of your server logic or adapt the code to make a silent login.  
J

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 2, 2017, 11:13am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/6 "2017-10-02T11:13:05Z")

</div>

Hi @jsantari. Please share me the code for silent login. I don’t know how to change my code to the ionic way ? Any ideas ?  
Thanks for your help.

---

<div class="post-metadata">

**Author:** ![jsanta](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/jsanta/32/66466_2.png) [@jsanta](https://forum.ionicframework.com/u/jsanta)\
**Post date:** [October 2, 2017, 12:53pm UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/7 "2017-10-02T12:53:29Z")

</div>

if you don’t know what is JWT you have a nice reading ahead. lots of links and information so I won’t post any.  
In your app.module.ts file:

```auto
// Ref.: https://github.com/angular/angular/issues/11262
export function httpFactory(backend: XHRBackend, options: RequestOptions, global: AppState, toastCtrl: ToastController, eventService: EventsService) {
  return new ExtendedHttpService(backend, options, global, toastCtrl, eventService);
}

```

before the @ngMoidule declaration.  
And in the same file, in the providers section:

```auto
// Ref.: https://gist.github.com/mrgoos/45ab013c2c044691b82d250a7df71e4c#gistcomment-2041630
    {
      provide: Http,
      useFactory: httpFactory,
      deps: [XHRBackend, RequestOptions, AppState, ToastController, EventsService]
   }

```

Remember to import all required dependencies.

In our project we had to make a complete “extended-http.service.ts” to handle expired tokens in a silent way (here goes the complete file):

```auto
// Ref.: https://gist.github.com/mrgoos/45ab013c2c044691b82d250a7df71e4c
import { Injectable } from '@angular/core';
import { Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

import { ToastController } from "ionic-angular";
import { AppState } from "../app/app.global";
import { EventsService } from "./events-service";

@Injectable()
export class ExtendedHttpService extends Http {    

  constructor(backend: XHRBackend, 
    defaultOptions: RequestOptions,
    public global: AppState,
    public toastCtrl: ToastController,
    public eventService: EventsService) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    //do whatever 
    if (typeof url === 'string') {
      if (!options) {        
        options = { headers: new Headers() };        
      }
      this.setHeaders(options);
    } else {
      this.setHeaders(url);
    }    

    return super.request(url, options).catch(this.catchErrors());
  }

  private catchErrors() {
    return (res: Response) => {
      if (res.status === 401 || res.status === 403) {
          let jsonRes: any = res.json();
          console.log('http interceptor catchErrors', jsonRes);          
          
          if(jsonRes.errorCode === 11){ // Token has expired
            this.refreshToken(this.global.get('refreshToken'))
                .map((res) => res.json() )
                .subscribe((data) => {
                        console.log('refreshToken', data);
                        let newToken: string = data.token;                    
                        this.global.set('token', newToken);                    
                    },
                    err => {
                        let jsonErr: any = err.json();
                        if(jsonErr.error === 'Unauthorized' && jsonErr.path === '/api/token'){
                            // RefreshToken has expired
                            // Show toast "Debe reingresar sus credenciales"                        
                            this.presentToast('Debe reingresar sus credenciales.', true, 'LoginPage');
                        }             
                    }
                );
          }        
        
        if(res.status === 403){
            this.presentToast('Debe reingresar sus credenciales.', true, 'LoginPage');
        }          
      }
      return Observable.throw(res);
    };
  }

  private setHeaders(objectToSetHeadersTo: Request | RequestOptionsArgs) {
    //add whatever header that you need to every request
    //in this example I add header token by using authService that I've created
    objectToSetHeadersTo.headers.set('Content-Type', 'application/json');
    objectToSetHeadersTo.headers.set('X-Requested-With', 'XMLHttpRequest'); 
    
    let token: string = this.global.get('token');
    token = (!!token)?token:'';
    objectToSetHeadersTo.headers.set('X-Authorization', 'Bearer ' + token);       
  }

  
  private refreshToken(refreshToken: string = ''): Observable<Response> {
      let BASE_URL: string = this.global.get('apiServer');      
      let headers: Headers = new Headers();      

      headers.append('Content-Type', 'application/json');
      headers.append('X-Requested-With', 'XMLHttpRequest');    
      headers.append('X-Authorization', 'Bearer ' + refreshToken);

      return super.request(BASE_URL + '/token', { headers: headers });
  }

  private toastActive: boolean = false;
  private presentToast(message: string, showCloseButton: boolean = false, targetPage?: string) {    

    if(!this.toastActive){
        let toast = this.toastCtrl.create({
            message: message,
            duration: (!showCloseButton)?1750:undefined,
            showCloseButton: showCloseButton,
            closeButtonText: 'Cerrar',
            position: 'bottom',
            dismissOnPageChange: true
        });   
        toast.dismissAll();

        toast.present().then(() => {
            this.toastActive = true;
            toast.onDidDismiss(() => {
                console.log('Dismissed toast');
                this.toastActive = false;                
                if(!!targetPage){                
                    this.eventService.broadcast('openPage', targetPage);
                }
            });
        });
    }
    
  }
}

```

We also use an EventService (found in [https://stackoverflow.com/questions/34700438/global-events-in-angular-2](https://stackoverflow.com/questions/34700438/global-events-in-angular-2) )  
to call other module’s functions using event broadcasting (kind of ala AngularJS way).  
Please try to understand the code, don’t just copy & paste it, otherwise you wion’t even understand how to solve your problem.

Best regards.  
J

---

<div class="post-metadata">

**Author:** ![rapropos](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/rapropos/32/100227_2.png) [@rapropos](https://forum.ionicframework.com/u/rapropos)\
**Post date:** [October 2, 2017, 7:34pm UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/8 "2017-10-02T19:34:54Z")

</div>

The advice in the previous post is obsoleted by the Angular 4.3 `HttpClient`.

---

<div class="post-metadata">

**Author:** ![jsanta](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/jsanta/32/66466_2.png) [@jsanta](https://forum.ionicframework.com/u/jsanta)\
**Post date:** [October 2, 2017, 9:11pm UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/9 "2017-10-02T21:11:29Z")

</div>

Maybe so, but it helps in understanding the new API.  
Here’s a good article for the afternoon reading [https://blog.angularindepth.com/the-new-angular-httpclient-api-9e5c85fe3361](https://blog.angularindepth.com/the-new-angular-httpclient-api-9e5c85fe3361)  
(the interceptor part is the one that can help you @Peter_D )

Best regards,  
J

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 3, 2017, 2:18am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/10 "2017-10-03T02:18:23Z")

</div>

Thanks @jsanta and @rapropos very much. I’m going to check it now

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 3, 2017, 9:13am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/11 "2017-10-03T09:13:10Z")

</div>

I’ve added observable to function checkToken(), but It doesn’t return the data as I want, It returned Observable {\_isScalar: false,…}. How can I get the data ?

```auto
  getToken():Observable<any> {
     return Observable.fromPromise( this.storage.get('user').then((user) => {
      if(user) {
        this.token = user.token;
        this.token_date = user.token_date - 100;
        this.currentDate = new Date();
        this.expDate = new Date(this.token_date * 1000);
        if (this.expDate === this.currentDate) {
          // token expired, login again     
          console.log('first');  
    let headers = new Headers();
    headers.append('Access-Control-Allow-Origin', '*');
    headers.append('Access-Control-Allow-Methods', '*');
    headers.append('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');    
    let body = {
      "user_id" : identifi,
      "password" : password
    };
    let options = new RequestOptions({ headers: headers });
    return this.http.post(api.logIn, body, options).map((res:Response) => res.json());
        }
      }
    })
)
  }

  getDataHomepage(retailerId: number,pageIndex: number) {
          this.checkToken().subscribe(
            data => {
              console.log(data); //return Observable {_isScalar: false,...}
            });
    let headers = new Headers();
    headers.append('Authorization', 'Bearer ' + this.token);
    let options = new RequestOptions({ headers: headers });
    return this.http.get(api.promotion + '?retailer_id=' + retailerId + '&page=' + pageIndex, options).map((res:Response) => res.json());
  }

```

---

<div class="post-metadata">

**Author:** ![Peter\_D](https://avatars.discourse-cdn.com/v4/letter/p/3d9bf3/32.png) [@Peter\_D](https://forum.ionicframework.com/u/Peter_D)\
**Post date:** [October 4, 2017, 7:13am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/12 "2017-10-04T07:13:15Z")

</div>

Still stuck…Anyone can help me ?

---

<div class="post-metadata">

**Author:** ![jsanta](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/jsanta/32/66466_2.png) [@jsanta](https://forum.ionicframework.com/u/jsanta)\
**Post date:** [October 5, 2017, 10:31am UTC](https://forum.ionicframework.com/t/silent-login-when-token-expired/107127/13 "2017-10-05T10:31:22Z")

</div>

Unless your function is called in the exact millisecond, your code will never enter the expired block ( currentDate \>== expiredDate will work better, even better using millis instead of Date, formatted dates are for us humans, machine works better with plain numbers).

Also I see no need to make a observable out of a promise, http post id already returning an observable, just chain the map before subscribing to checkToken.
