Reputation: 817
So firstly a bit of context. I have an angular 2 dashboard, it sits behind a login and has signalr integrated too. For request sent via angular's http client i can use a url interceptor check if the token has expired and if so request a new token from the api. This works great for all authenticated calls except with signalr.
With signalr upon logging in we establish a connection and send up the bearer token as part of the query string. However since signalr is separate is does not use angular s http client and therefore the url interceptor is not hit. I have been thinking of different ways to handle this and for me the cleanest one would be to subscribe to an observable that fires when the token expires.
So now my question is if i have an expiration date, can i write an observable that triggers say when expiration time is five minutes before the current time. This way i could subscribe to that observable in my signalr service and disconnect and connect with the updated auth token. I can provide code samples if needed but i don't know how much help they will be with my question.
Thank you for any help with this.
Upvotes: 0
Views: 1869
Reputation: 12960
I don't know about signalr but I can give a solution for your requirement.
You can use timer
from rxjs
, this is just like setTimeout()
, but just an Observable.
Create Date Objects for the expirationDate
and another for five minutes before expiration date. Subtract them to find the time in which Observable should fire.
Pass the time
in milliseconds to the timer where you can do your subscription. Once the API call is done, call the same method again to reInitialize the timer.
timerSubs: Subscription; // to cancel existing timer
ngOnInit() {
this.calculateTimeForTimer()
}
calculateTimeForTimer() {
let expirationDate = new Date();
expirationDate.setTime(expirationDate.getTime() + 10 * 1000); // 10 seconds from now.
// in your case use your own duration/date of expiration
let alertDate = new Date(expirationDate);
alertDate.setTime(alertDate.getTime() - 5 * 1000); // 5 seconds before expiration
// in your case subtract 5 minutes instead of 5 seconds
let timeDuration = (expirationDate.getTime() - alertDate.getTime());
this._startTimer(timeDuration);
}
private _startTimer(timeDuration) {
if (this.timerSubs) {
this.timerSubs.unsubscribe();
}
this.timerSubs = timer(timeDuration).subscribe((data) => {
// make the API call, and then calculate appropriate duartion and call startTimer() again
of("This is your new Token").pipe(delay(2000)).subscribe((apiData) => {
console.log("Data from API", apiData);
this.calculateTimeForTimer();
})
})
}
See a sample here, it has 10 seconds as expiration date from current time. https://stackblitz.com/edit/angular-bhupgg
Upvotes: 1
Reputation: 1809
This observer would do that
const tokenTimeout = timeout;
let currentTime = new Date();
return new Observable(observer => {
while(tokenTimeout > currentTime) {
currentTime = new Date();
}
observer.next();
observer.complete();
});
As an alternative, when you register a client connection on the server register their token time out with the client registration, then when sending a message to the client check the timeout, and if it's elapsed first send a message to the client to renew their token, then on the client side in JS have a method that renews the token. This article talks about registering client connections. I think this would have less of a potential to fail.
Upvotes: 0