Last active
October 24, 2017 06:32
-
-
Save kilgarenone/e59e300084b58b4e33e87d16ef973087 to your computer and use it in GitHub Desktop.
Angular2 + RxJS: Call refresh token api to get a new access token and then automatically retry the previous http request with the new access token
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface RebuildRequest { | |
type: string; | |
args: { | |
path: string; | |
body?: string; | |
opt: RequestOptions; | |
} | |
}; | |
// a http request method | |
get(): Observable<any> { | |
// build your headers and url here | |
return this.processObs( | |
this.http.get(path, opt), | |
{ | |
type: 'get', | |
args: { path, opt } | |
}); | |
} | |
/** | |
* Post-Process on Observable object | |
* | |
* @private | |
* @param {Observable<any>} obv | |
* @param {object} obj | |
* @returns {Observable<any>} | |
* @memberof ApiService | |
*/ | |
private processObs(obv: Observable<any>, obj: object): Observable<any> { | |
return obv | |
.catch((err: Response) => this.errorHandler.refreshToken(err, obj)) // catch your 401 Unauthorized error | |
.map((res) => { // receives the original request's response | |
const data = res.json(); | |
return data ? data.data : data || {}; | |
}) | |
.catch(this.errorHandler.processApiError.bind(this.errorHandler)); // catch original or retried request's non-401 errors | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Call refresh token api to get and store the new access token, | |
* then return it as an observable back to the original stream | |
* | |
* @param {Response} err | |
* @param {{ type: string, args: { path: string, body?: string, opt: RequestOptions } }} obj | |
* @returns | |
* @memberof ErrorHandlerService | |
*/ | |
refreshToken(err: Response, obj: RebuildRequest) { | |
if (err.status === 401) { | |
// construct your new request here | |
// call refresh token api and return the new access token | |
return this.sessionService.renewAccessToken() | |
.switchMap((newToken) => { // switch to your new request observable | |
// set with the new access token | |
obj.args.opt.headers.set('Authorization', 'bearer ' + newToken) | |
return this.http[obj.type](...Object.values(obj.args)); | |
}); | |
} else { | |
// throw other kind of errors to be caught by the second | |
// catch method in the processObs method. | |
return Observable.throw(err); | |
} | |
} | |
// handle your non-401 errors here | |
processApiError(response: Response) { | |
if (response.status === 500) { | |
// do stuff | |
return Observable.throw(response.statusText); | |
} else if (response.status >= 400 && response.status < 500) { | |
// do stuff | |
return Observable.throw(response.error_message) | |
} else { | |
// do stuff | |
return Observable.throw('Unknown Error'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
renewAccessToken(): Observable<any> { | |
// if no refresh token is found in session storage, | |
// clean up and route to login page | |
if (!this.refreshToken) { | |
this.clear(); | |
this.router.navigate([environment.loginRoute]); | |
return Observable.throw('No Refresh Token'); | |
} | |
// construct the refresh token query parameter | |
const queries = new URLSearchParams(); | |
queries.append('refreshToken', this.refreshToken); | |
const options = new RequestOptions({ params: queries }); | |
// call the refresh token api | |
return this.http.get( | |
environment.apiUrl + OAuth.token, | |
options | |
).map((response) => { | |
// set the new access token and refresh token | |
this.token = response.json()['data'].access_token; | |
this.refreshToken = response.json()['data'].refresh_token; | |
return this.token; | |
}).catch((err) => { | |
// clear session and redirect to login if failed to get refresh token | |
this.clear(); | |
this.router.navigate([environment.loginRoute]); | |
return Observable.throw(err); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment