Skip to content

Instantly share code, notes, and snippets.

@usmansaleem
Created October 19, 2016 04:55
Show Gist options
  • Save usmansaleem/ea306e543a48f3ac2c4253984613591f to your computer and use it in GitHub Desktop.
Save usmansaleem/ea306e543a48f3ac2c4253984613591f to your computer and use it in GitHub Desktop.
Angular2 Login Service
import {Injectable} from "@angular/core";
import {Http, Headers, Response} from "@angular/http";
import {Observable} from "rxjs";
import "rxjs/add/operator/map";
/**
* Login Service to obtain access_token and refresh_token.
*/
@Injectable()
export class LoginService {
public access_token: string;
public refresh_token: string;
private readonly LOGIN_URL: string = '/api/auth/login';
private readonly REFRESH_URL: string = '/api/auth/token';
private readonly ACCESS_STORAGE_KEY: string = 'accessStorage';
private readonly REFRESH_STORAGE_KEY: string = 'refreshStorage';
constructor(private http: Http) {
// set token if saved in local storage
var accessStorage = JSON.parse(localStorage.getItem(this.ACCESS_STORAGE_KEY));
this.access_token = accessStorage && accessStorage.access_token;
var refreshStorage = JSON.parse(localStorage.getItem(this.REFRESH_STORAGE_KEY));
this.refresh_token = refreshStorage && refreshStorage.refresh_token;
}
login(username, password): Observable<boolean> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(this.LOGIN_URL, JSON.stringify({user: username, password: password}), {headers})
.map((response: Response) => {
// login successful if there's a jwt token in the response
let recieved_access_token = response.json() && response.json().access_token;
let recieved_refresh_token = response.json() && response.json().refresh_token;
if (recieved_access_token && recieved_refresh_token) {
// set token property
this.refresh_token = recieved_refresh_token;
this.access_token = recieved_access_token;
//TODO: Is this secure enough?
localStorage.setItem(this.ACCESS_STORAGE_KEY, JSON.stringify({
access_token: recieved_access_token
}));
localStorage.setItem(this.REFRESH_STORAGE_KEY, JSON.stringify({
user: username,
refresh_token: recieved_refresh_token
}));
// return true to indicate successful login
return true;
} else {
//this is not meant to happen. It means server message protocol has been changed.
this.logout();
return false;
}
}).catch(error => {
this.logout();
return Observable.throw(error);
});
}
/**
* Client side detection whether access token is expired or about to expire
* (i.e. considers expired a minute ahead of actual expiry).
*
* @returns {boolean}
*/
isAccessTokenExpired(): Boolean {
if (this.access_token == null) {
return true; //consider expired if we are not authenticated yet ...
}
var base64Url = this.access_token.split('.')[1];
if (base64Url) {
var base64 = base64Url.replace('-', '+').replace('_', '/');
var parsedToken = JSON.parse(window.atob(base64));
if (parsedToken) {
//divide by 1000 because of the way jwt dates are stored
//subtract 60000 milliseconds (i.e. 1 minutes) to expire token a minute ahead of actual expiry ...
return parsedToken.exp - 60000 <= Math.floor(Date.now() / 1000);
}
}
return true; //consider expired if access_token is not in valid jwt format.
}
refreshAccessToken(): Observable<Boolean> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(this.REFRESH_URL, JSON.stringify({refresh_token: this.refresh_token}), {headers})
.flatMap((response: Response) => {
// login successful if there's a jwt token in the response
let recieved_access_token = response.json() && response.json().access_token;
if (recieved_access_token) {
console.log("Refresh token request successful ... ");
// set token property
this.access_token = recieved_access_token;
// store access token in local storage
//TODO: Is this secure enough?
var accessDetails = JSON.parse(localStorage.getItem(this.ACCESS_STORAGE_KEY));
accessDetails.access_token = this.access_token;
localStorage.setItem(this.ACCESS_STORAGE_KEY, JSON.stringify(accessDetails));
return Observable.of(true);
} else {
//this is not meant to happen.
return Observable.of(false);
}
}).catch(requestError => {
if (requestError && requestError.status === 400) {
//we have our refresh token expired or revoked ... we should logout and rethrow this error further ...
this.logout();
}
return Observable.throw(requestError);
});
}
logout(): void {
console.log("Logging out...");
// clear token remove user from local storage to log user out
this.access_token = null;
this.refresh_token = null;
localStorage.removeItem(this.ACCESS_STORAGE_KEY);
localStorage.removeItem(this.REFRESH_STORAGE_KEY);
}
isLoggedIn(): Boolean {
//TODO: Should we check localstorage or rely on state of this class?
return !(this.refresh_token == null);
}
setAuthorizationHeader(headers: Headers): void {
headers.delete("Authorization");
headers.append("Authorization", `Bearer ` + this.access_token);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment