Angular2-jwt: Can't use promise within tokenGetter in

Created on 11 Aug 2016  路  9Comments  路  Source: auth0/angular2-jwt

I am using Ionic 2 with a custom Store provider to get/set token data using the native SecureStorage library with a LocalStorage fallback. However, when I attempt to use said store provider to get the token, then return the token from the promise, it appears that the tokenGetter does not wait for the promise to be completed before attempting to process the token.

ionicBootstrap( MyFancyApp, [
  Store,
  HTTP_PROVIDERS,
  AUTH_PROVIDERS,
  provide( AuthHttp, {
    useFactory: ( http, store ) => {
      return new AuthHttp( new AuthConfig({
        headerName: 'Authorization',
        headerPrefix: 'Bearer',
        tokenName: '',
        tokenGetter: ( () => {
          store.get('bearer').then( token => {
            console.log( token );
            return token;
          });
        }),
        globalHeaders: [{'Content-Type':'application/json'}]
      }), http );
    },
    deps: [ Http, Store ]
  })
]);

When I attempt to use AuthHttp to make a request, I get the following feedback in the console:
screen shot 2016-08-11 at 3 53 41 pm
It appears that the error is thrown by AuthHttp before the token is logged to the console, which is what leads me to think it isn't waiting for the promise. Any ideas? I'm pretty new to Angular 2 so I could just be doing this wrong. Thanks!

Most helpful comment

ok, i got it

function getAccessToken(http: Http): Promise<string> {
    let jwtHelper: JwtHelper = new JwtHelper();
    let accessToken = localStorage.getItem('access_token');
    if (jwtHelper.isTokenExpired(accessToken)) {    // token expire
        let authenService: AuthenService = new AuthenService(http, null, new UrlService());
        let refreshToken = localStorage.getItem('refresh_token');
        return new Promise((resolve, reject) => {
            authenService.refreshToken(refreshToken).subscribe(
                success => {                    //refresh_token success
                    let objResponse = JSON.parse(success._body);
                    localStorage.setItem('access_token', objResponse.access_token);
                    localStorage.setItem('refresh_token', objResponse.refresh_token);
                    resolve(objResponse.access_token);  //return new access_token
                },
                error => {
                    resolve(accessToken);       // if error send old access_token and then let it error 401
                }
            );
        });
    } else {
        return Promise.resolve(accessToken);    //token not expire
    }
}

All 9 comments

The token getter is a sync function and promises are async. We would have to rework the getter to accept promises (more likely observables).

Thanks for the reply @escardin, any chance of this happening or should I find another way?

Its an interesting idea, but I haven't the time to allocate to it. I'm sure a pull request would be welcome.

@escardin @ethanmay
I just made a Pull-Request for this issue :)

Can we get this working for Observables? I'd like to pull the token in from an Ngrx store.

@Ant59 It probably should have just been observables in the first place. For now, you can use observable.toPromise() in your token getter.

@escardin can you provide an example that how to use token getter as observable.toPromise().
This is my code but it not work. It call resource request before refresh token success.
thank you

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
    return new AuthHttp(new AuthConfig({
        tokenName: 'access_token',
        //tokenGetter: (() => localStorage.getItem('access_token')),
        tokenGetter: (() => getAccessToken(http)),
        globalHeaders: [{ 'Content-Type': 'application/json' }],
    }), http, options);
}
function getAccessToken(http: Http):  Promise<string>{
    let jwtHelper: JwtHelper = new JwtHelper();
            let accessToken = localStorage.getItem('access_token');
            let urlService:UrlService = new UrlService();
            if (jwtHelper.isTokenExpired(accessToken)) {
                //token expire
                let authenService: AuthenService = new AuthenService(http,null,urlService);
                let refreshToken = localStorage.getItem('refresh_token');
                authenService.refreshToken(refreshToken).subscribe(
                    success => {
                        //refresh_token success
                        let objResponse = JSON.parse(success._body);
                        localStorage.setItem('access_token', objResponse.access_token);
                        localStorage.setItem('refresh_token', objResponse.refresh_token);
                        let newAccessToken = localStorage.getItem('access_token');
                        return new Promise((resolve, reject) => {
                            resolve(newAccessToken);
                        });
                    }, 
                    error => {
                        // if error send old access_token and then let it error 401
                         return new Promise((resolve, reject) => {
                            resolve(accessToken);
                        });  
                    }
                );
            } else {
                //token not expire
                 return new Promise((resolve, reject) => {
                    resolve(accessToken);
                }); 
            }
}

ok, i got it

function getAccessToken(http: Http): Promise<string> {
    let jwtHelper: JwtHelper = new JwtHelper();
    let accessToken = localStorage.getItem('access_token');
    if (jwtHelper.isTokenExpired(accessToken)) {    // token expire
        let authenService: AuthenService = new AuthenService(http, null, new UrlService());
        let refreshToken = localStorage.getItem('refresh_token');
        return new Promise((resolve, reject) => {
            authenService.refreshToken(refreshToken).subscribe(
                success => {                    //refresh_token success
                    let objResponse = JSON.parse(success._body);
                    localStorage.setItem('access_token', objResponse.access_token);
                    localStorage.setItem('refresh_token', objResponse.refresh_token);
                    resolve(objResponse.access_token);  //return new access_token
                },
                error => {
                    resolve(accessToken);       // if error send old access_token and then let it error 401
                }
            );
        });
    } else {
        return Promise.resolve(accessToken);    //token not expire
    }
}

Hi, I am trying to do the same but the requests are taking the promise before it gets completed and failing to get the updated token.
Below is my code to get the token:

export class TokenService {

refresh = false;

constructor(public injector: Injector) {
}

public getToken(): string | Promise<string> {
    const jwtHelper = new JwtHelperService();

    let token = localStorage.getItem('token');
    let refreshToken = localStorage.getItem('refreshToken');

    if (!token || !refreshToken) {
        return null;
    }

    if (jwtHelper.isTokenExpired(token)) {
        if (jwtHelper.isTokenExpired(refreshToken)) {
            return null;
        } else {
            let tokenPromise;
            if (!this.refresh) {
                this.refresh = true;
                tokenPromise = this.promiseFromObservable(this.getTokenService(localStorage.getItem('refreshToken')));
            }
            return tokenPromise;
        }
    } else {
        return token;
    }
}

getTokenService(refreshToken: string) {
    let http = this.injector.get(HttpClient);

    const httpOptions = {
        headers: new HttpHeaders({
            'Authorization': 'Bearer ' + refreshToken
        })
    };
    return http.post<Tokens>(location.origin + '/LiveTime/services/v1/auth/tokens?locale=en', null, httpOptions);
}

promiseFromObservable(o): Promise<string> {
    return new Promise((resolve, reject) => o.subscribe((token: Tokens) => resolve(token.token),reject(), err => { console.log(err); return null; }))
        .then((token: Tokens) => {
            localStorage.setItem('token', token.token);
            localStorage.setItem('refreshToken', token.refreshToken);
            this.refresh = false;
            return token.token;
        },
            err => { console.log(err); return null; }
        )
        .catch((error) => { console.log(error);reject();
        });
}

}

Can someone tell me what is wrong in this code?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ciesielskico picture ciesielskico  路  5Comments

jaumard picture jaumard  路  5Comments

kolkov picture kolkov  路  3Comments

sfabriece picture sfabriece  路  4Comments

dmitrybz picture dmitrybz  路  4Comments