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:

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!
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?
Most helpful comment
ok, i got it