<file_sep>
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { UserAuthService } from '../services/user-auth.service';
import { ROUTE } from '../app.constants';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(
    private router: Router,
    private userAuthService: UserAuthService) { }

  canActivate() {
    if (!this.userAuthService.isTokenExpired()) {
      return true;
    }

    this.router.navigate(['/' + ROUTE.SESSION_TIMEOUT]);
    return false;
  }

}<file_sep>/**
 * 
 */

const TOKEN_KEY: string = "tcc_auth_token";
const RESP_TOKEN_KEY: string = "token";

export class StorageHelper {
  static get(key): string {
    return localStorage.getItem(key);
  }
  static set(key, value): void {
    localStorage.setItem(key, value);
  }

  static getToken(): string {
    return this.get(TOKEN_KEY);
  }

  static setToken(value): void {
    this.set(TOKEN_KEY, value);
  }

  static saveTokenFromResponse(resp): void {
    let token = resp.headers.get(RESP_TOKEN_KEY);
    if(token != undefined && token != null) {
      this.setToken(token);
    }
  }
}<file_sep>import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { StorageHelper } from './storage-helper';
import { NGXLogger } from 'ngx-logger';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private storage: StorageHelper, private logger: NGXLogger) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    this.logger.info("AuthInterceptor:", request.url);

    // Send token except for login & get user role: 
    if (request.url.indexOf('/auth') == -1) {
      // add authorization header with jwt token if available
      let token = StorageHelper.getToken();
      if (token) {
        request = request.clone({
          setHeaders: {
            Authorization: token
          }
        });
      }
    }
    return next.handle(request);
  }
}<file_sep>//Install express server
const express = require('express');
const path = require('path');

var bodyParser = require('body-parser')
const app = express();

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json());

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, token_type, access_token, refresh_token, expiry_date');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});

// Flatfile Database: 
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')

const adapter = new FileSync('db.json')
const db = low(adapter)
db.defaults({ users: [], count: 0 }).write()


/**** BACKEND SERVER ****/
app.get('/server/users', function(req, res) {
    res.send({ status: 1, result: db.get('users').value() });
});
app.post('/server/users', function(req, res) {
    db.get('users').push(req.body).write();
    res.send({ status: 1 });
});

/**** FRONTEND ANGULAR APP ****/
// Serve only the static files form the dist directory
app.use(express.static(__dirname + '/dist/ng-bootstrap-starter'));

app.get('/*', function(req,res) {
    res.sendFile(path.join(__dirname+'/dist/ng-bootstrap-starter/index.html'));
});

// Start the app by listening on the default Heroku port
var port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on port ${port}`));


<file_sep>import { Injectable } from '@angular/core';
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';
import { NGXLogger } from 'ngx-logger';
import { Observable } from 'rxjs';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/materialize';
import 'rxjs/add/operator/dematerialize';

import { URL, USER_ROLE } from '../app.constants';

@Injectable()
export class FakeBackendInterceptor implements HttpInterceptor {
    dummyTokenHeader = new HttpHeaders({'token' : 'fake-token <PASSWORD>'});

    constructor(private logger: NGXLogger) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        
        this.logger.info("FakeBackend:", request.url);
        
        // wrap in delayed observable to simulate server api call
        return Observable.of(null).mergeMap(() => {

            if (request.url.indexOf(URL.GET_USER) != -1) {
                let data = {
                    id: 1234,
                    username: 'manishg',
                    firstName: '<NAME>',
                    lastName: 'Ganta'
                };
                return Observable.of(new HttpResponse({ status: 200, body: data, headers: this.dummyTokenHeader }));
            }

            else if (request.url.indexOf(URL.REGISTER) != -1) {                
                let resp = {
                    status: 'success',
                    message: 'user created',
                    user_id: 1234
                }
                return Observable.of(new HttpResponse({ status: 200, body: resp }));
            }

            // authenticate
            else if (request.url.indexOf(URL.LOGIN) != -1 && request.method === 'POST') {
                // find if any user matches login credentials
                let userPasswordValid = false;
                if(request.body.user == 'demouser' && request.body.password == '<PASSWORD>') {
                    userPasswordValid = true;
                }
                if (userPasswordValid) {
                    // if login details are valid return 200 OK with user details and fake jwt token
                    let data = {
                        id: 1234,
                        username: 'demouser',
                        firstName: 'Demo',
                        lastName: 'User'
                    };

                    return Observable.of(new HttpResponse({ status: 200, body: data, headers: this.dummyTokenHeader }));
                } else {
                    // else return 400 bad request
                    return Observable.throw('Username or password is incorrect');
                }
            }

            // pass through any requests not handled above
            return next.handle(request);
            
        })

        // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
        .materialize()
        .delay(500)
        .dematerialize();
    }
}

export let FakeBackendProvider = {
    // use fake backend in place of Http service for backend-less development
    provide: HTTP_INTERCEPTORS,
    useClass: FakeBackendInterceptor,
    multi: true
};<file_sep>
export const APP_TITLE = "Angular6 + Bootstrap";

// User Roles: 
export const USER_ROLE = {
    ADMIN: "admin",
    USER: "user"
}

// URL constants: 
export const URL = {
    LOGIN       : '/server/login',
    REGISTER    : '/server/create_user',
    GET_USER    : '/server/get_user',
    UPDATE_USER : '/server/update_user'
};

// Routes:
export const ROUTE = {
    SESSION_TIMEOUT: 'session-timeout',
    HOME: 'home',
    FEATURES: 'features',
    CONTACT: 'contact',
    REGISTER: 'register',
    MY_PROFILE: 'my-profile'
}
<file_sep>// show-errors.component.ts
import { Component, Input } from '@angular/core';
import { AbstractControlDirective, AbstractControl, NgForm, NgModel } from '@angular/forms';

@Component({
  selector: 'show-errors',
  template: `
   <ul *ngIf="shouldShowErrors()" style="list-style:none;padding:0;">
     <li style="color: red" *ngFor="let error of listOfErrors()">{{error}}</li>
   </ul>
 `,
})
export class ShowErrorsComponent {

  private static readonly errorMessages = {
    'required': () => 'Entry required',
    'minlength': (params) => 'Minimum characters are ' + params.requiredLength,
    'maxlength': (params) => 'Maximum characters are ' + params.requiredLength,
    'pattern': (params) => 'Invalid entry', // 'The required pattern is: ' + params.requiredPattern,
    'years': (params) => params.message,
    'countryCity': (params) => params.message,
    'uniqueName': (params) => params.message,
    'telephoneNumbers': (params) => params.message,
    'telephoneNumber': (params) => params.message
  };

  @Input() private f: NgForm;
  @Input() private control: NgModel;
  @Input() private sameValue: NgModel;
  @Input() private notSameValue: NgModel;
  @Input() private other: NgModel;
  @Input() private invalidVal: string;
  @Input() private alreadyTaken:boolean

  shouldShowErrors(): boolean {
    let ret = this.control &&
      this.control.errors &&
      (this.control.dirty || this.control.touched || this.f.submitted) ||
      (this.control.touched && this.sameValue != undefined && this.sameValue.value != this.control.value) ||
      (this.control.touched && this.notSameValue != undefined && this.notSameValue.value == this.control.value) ||
      (this.invalidVal != undefined && this.control.value == this.invalidVal)||this.alreadyTaken;

    if (this.other != undefined) {
      // ret - true means, there is an error, now check other field
      ret = ret && (this.other.value == undefined || this.other.value == '');
    }
    return ret;
  }

  listOfErrors(): string[] {
    if (this.other != undefined && (this.other.value == undefined || this.other.value == '')) {
      // return ["Either " + this.other.name + " or " + this.control.name + " is required"];
      return ["Entry Required"];
    }
    if (this.invalidVal != undefined && this.control.value == this.invalidVal) {
      return ["Invalid value"];
    }

    if (this.sameValue != undefined) {
      if (this.sameValue.valid && this.sameValue.value != this.control.value) {
        let name = this.sameValue.name;
        if(name == "newpassword") {
          name = "New Password";
        }
        return [ name + " must match" ];
      }
    }
    if (this.notSameValue != undefined) {
      if (this.notSameValue.valid && this.notSameValue.value == this.control.value) {
        return ["must not be same as " + this.notSameValue.name];
      }
    }
   
    if(this.alreadyTaken){
      return [this.control.name +" already in use"];
    }

    if(this.control.errors != undefined && this.control.errors != null) {
    return Object.keys(this.control.errors)
      .map(field => this.getMessage(field, this.control.errors[field]));
    }
    return [];
  }

  private getMessage(type: string, params: any) {
    return ShowErrorsComponent.errorMessages[type](params);
  }

}<file_sep>import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { LoggerModule, NgxLoggerLevel } from 'ngx-logger';
import { AngularFontAwesomeModule } from 'angular-font-awesome';
import { LoadingBarRouterModule } from '@ngx-loading-bar/router';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { SocialLoginModule, AuthServiceConfig } from "angularx-social-login";
import { GoogleLoginProvider, FacebookLoginProvider, LinkedInLoginProvider} from "angularx-social-login";

import { AppComponent } from './app.component';
import { AppRouting } from './app.routing';

import { SessionTimeoutComponent } from './components/session-timeout.component';
import { HeaderComponent } from './components/partials/header/header.component';
import { FooterComponent } from './components/partials/footer/footer.component';
import { LoadingComponent } from './components/partials/loading/loading.component';
import { MyProfileComponent } from './components/my-profile/my-profile.component';

import { Utils } from './services/utils';
import { UserAuthService } from './services/user-auth.service';

import { FakeBackendProvider } from './helpers/fake-bakend';
import { environment } from '../environments/environment';
import { AuthGuard } from './helpers/auth.gaurd';
import { HomeComponent } from './components/home/home.component';
import { FeaturesComponent } from './components/features/features.component';
import { ContactComponent } from './components/contact/contact.component';
import { RegisterComponent } from './components/register/register.component';
import { ShowErrorsComponent } from './components/partials/show-errors.component';

export function getAuthServiceConfigs() {
  let config = new AuthServiceConfig(
      [
        {
          id: GoogleLoginProvider.PROVIDER_ID,
          provider: new GoogleLoginProvider("1004357134903-s4mrfph41nhptm713rtun4h0v1t1svug.apps.googleusercontent.com")
        },
        {
          id: FacebookLoginProvider.PROVIDER_ID,
          provider: new FacebookLoginProvider("471510306668438")
        },
        // {
        //   id: LinkedInLoginProvider.PROVIDER_ID,
        //   provider: new LinkedInLoginProvider("81n843y6hvssco", true, 'en_US')
        // },
      ]
  );
  return config;
}

@NgModule({
  declarations: [
    AppComponent,
    SessionTimeoutComponent,
    HeaderComponent,
    FooterComponent,
    LoadingComponent,
    MyProfileComponent,
    HomeComponent,
    FeaturesComponent,
    ContactComponent,
    RegisterComponent,
    ShowErrorsComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    FormsModule,
    AppRouting,
    AngularFontAwesomeModule,
    SocialLoginModule,
    LoggerModule.forRoot({ 
      level: environment.production ? NgxLoggerLevel.LOG : NgxLoggerLevel.DEBUG,
      serverLogLevel: NgxLoggerLevel.OFF 
    }),
    LoadingBarRouterModule
  ],
  providers: [
    Utils,
    AuthGuard,
    UserAuthService,
    {
      provide: AuthServiceConfig,
      useFactory: getAuthServiceConfigs
    },
    FakeBackendProvider
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
<file_sep>import { Component, OnInit } from '@angular/core';
import { fadeAnimation } from './animations';

@Component({
  selector: 'app-root',
  template: `
  <ngx-loading-bar [includeBar]='true' [includeSpinner]='false'></ngx-loading-bar>
  <div [@fadeAnimation]="o.isActivated ? o.activatedRoute : ''">
    <router-outlet #o="outlet"></router-outlet>    
  </div>`,
  animations: [fadeAnimation]
})

export class AppComponent implements OnInit {
  constructor() { }

  ngOnInit() {
   
  }
}
<file_sep>
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
import { NGXLogger } from 'ngx-logger';
import { ROUTE } from '../app.constants';

@Injectable()
export class AuthErrorHandler implements ErrorHandler {

  constructor(private injector: Injector, private logger: NGXLogger) { }

  handleError(error) {

    if (error != undefined || error != null){
      if (error.status === 401 || error.status === 403) {
        this.logger.error("Auth error", error);
        const router = this.injector.get(Router);
        router.navigate(['/' + ROUTE.SESSION_TIMEOUT]);
      } else if (error.status === 502) {
        this.logger.error("Proxy error", error);
      }
    }
    throw error;
  }
}<file_sep>import { Component, OnInit, AfterViewInit } from '@angular/core';

import { AuthService } from "angularx-social-login";
import { FacebookLoginProvider, GoogleLoginProvider, LinkedInLoginProvider } from "angularx-social-login";

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit, AfterViewInit {

  menu: HTMLElement;
  panelMenu: NodeListOf<HTMLElement>;
  panelBoxes: NodeListOf<HTMLElement>;
  signUp: HTMLElement;
  signIn: HTMLElement;

  emailLogin: boolean = false;

  user: any = {
    name: '',
    email: '',
    password: ''
  }

  constructor(private socialAuthService: AuthService) { }

  ngOnInit() {
  }

  ngAfterViewInit() {
    this.menu = document.getElementById('menu');
    this.panelMenu = this.menu.querySelectorAll('li');
    this.panelBoxes = document.querySelectorAll('.panel__box');
    this.signUp = document.getElementById('signUp');
    this.signIn = document.getElementById('signIn');
  }

  removeSelection() {
    for (var i = 0, len = this.panelBoxes.length; i < len; i++) {
      this.panelBoxes[i].classList.remove('active');
      this.panelBoxes[i].classList.remove('inactive');
    }
    this.signUp.classList.remove("active");
    this.signIn.classList.remove("active");
  }

  public socialSignIn(socialPlatform : string) {
    let socialPlatformProvider;
    if(socialPlatform == "facebook"){
      socialPlatformProvider = FacebookLoginProvider.PROVIDER_ID;
    }else if(socialPlatform == "google"){
      socialPlatformProvider = GoogleLoginProvider.PROVIDER_ID;
    } else if (socialPlatform == "linkedin") {
      socialPlatformProvider = LinkedInLoginProvider.PROVIDER_ID;
    }
    
    this.socialAuthService.signIn(socialPlatformProvider).then(
      (userData) => {
        console.log(socialPlatform+" sign in data : " , userData);
        // Now sign-in with userData
        // ...
            
      }
    );
  }

  signOut(): void {
    this.socialAuthService.signOut();
  }

  onClickSignIn(e) {
    e.preventDefault();
    this.removeSelection();
    this.panelBoxes[0].classList.add('active');
    this.panelBoxes[1].classList.add('inactive');
    this.menu.classList.remove('second-box');
    this.signIn.classList.add("active");
  }

  onClickSignUp(e) {
    e.preventDefault();
    this.removeSelection();
    this.panelBoxes[1].classList.add('active');
    this.panelBoxes[0].classList.add('inactive');
    this.menu.classList.add('second-box');
    this.signUp.classList.add("active");
  }

  signInSubmit() {
    
  }
}
<file_sep>import { NGXLogger } from "ngx-logger";
import { HttpClient } from "@angular/common/http";
import { Router } from "@angular/router";
import { StorageHelper } from "../helpers/storage-helper";
import { Injectable } from "@angular/core";
import { ROUTE } from "../app.constants";

@Injectable()
export class Utils {

  constructor(
    private logger: NGXLogger,
    private http: HttpClient,
    private router: Router) { }

  invokeHttp(url, type = "GET", payload = {}) {
    let httpRsp;
    if(type == "POST") {
      httpRsp = this.http.post<any>(url, payload, { observe: 'response' });
    } else {
      httpRsp = this.http.get<any>(url, { observe: 'response' });
    }
    return httpRsp.map(resp => {
      if (resp.status == 403) {
        this.router.navigate(['/' + ROUTE.SESSION_TIMEOUT]);
        return
      }
      StorageHelper.saveTokenFromResponse(resp);
      let data: any = resp.body;
      return data;
    });
  }

  httpGet(url) {
    return this.invokeHttp(url);
  }

  httpPost(url, postData) {
    return this.invokeHttp(url, "POST", postData);
  }

  getParamsFromUrl(inputURL: string) {
    var query = inputURL;
    var result = {};
    query.split("&").forEach(function (part) {
      var item = part.split("=");
      result[item[0]] = decodeURIComponent(item[1]);
    });
    return result;
  }
}<file_sep>import { Injectable } from "@angular/core";

import * as jwt_decode from "jwt-decode";
import { StorageHelper } from '../helpers/storage-helper';
import { NGXLogger } from 'ngx-logger';
import { URL } from '../app.constants';
import { Utils } from './utils';
import { environment } from "../../environments/environment";

@Injectable()
export class UserAuthService {

  constructor(private utils: Utils, private logger: NGXLogger) { }

  getToken(): string {
    return StorageHelper.getToken();
  }

  setToken(token: string): void {
    StorageHelper.setToken(token);
  }

  getTokenExpirationDate(token: string): Date {
    if (!environment.production && token.split(" ")[0] == 'fake-token') {
      let date = new Date();
      return new Date(date.getTime() + 10 * 60000);
    }

    // First split, becasue from the server we are getting "Bearer <>"
    token = token.split(" ")[1];
    const decoded = jwt_decode(token);
    if (decoded['exp'] === undefined) {
      return null;
    }

    this.logger.info("Token expires at: ", decoded['exp']);
    const date = new Date(0);
    date.setUTCSeconds(decoded['exp']);
    return date;
  }

  isTokenExpired(token?: string): boolean {
    if (!token) token = this.getToken();
    if (!token || token == undefined || token == '' || token == null) return true;
    const date = this.getTokenExpirationDate(token);
    if (date === undefined) return false;
    return !(date.valueOf() > new Date().valueOf());
  }  
}<file_sep>import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-session-timeout',
  template: `<div class="text-center" style="padding-top: 200px; height: 100%;">
  <h1>Your session has timedout! Please login again..</h1>
</div>`,
})
export class SessionTimeoutComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}
<file_sep>import { RouterModule, Routes } from '@angular/router';
import { SessionTimeoutComponent } from './components/session-timeout.component';
import { AuthGuard } from './helpers/auth.gaurd';
import { ROUTE } from './app.constants';
import { MyProfileComponent } from './components/my-profile/my-profile.component';
import { HomeComponent } from './components/home/home.component';
import { FeaturesComponent } from './components/features/features.component';
import { ContactComponent } from './components/contact/contact.component';
import { RegisterComponent } from './components/register/register.component';

const routes: Routes = [
    { path: ROUTE.SESSION_TIMEOUT, component: SessionTimeoutComponent },
    { path: ROUTE.REGISTER, component: RegisterComponent },
    { path: ROUTE.HOME, component: HomeComponent },
    { path: ROUTE.FEATURES, component: FeaturesComponent },
    { path: ROUTE.CONTACT, component: ContactComponent },
    
    // Private routes 
    { path: ROUTE.MY_PROFILE, component: MyProfileComponent, canActivate: [AuthGuard] },

    // Default Route:
    { path: '**', component: RegisterComponent },
    
];
export const AppRouting = RouterModule.forRoot(routes ,{useHash:true});