npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ng5plus-auth

v1.1.0

Published

Angular 5+ authentication service.

Downloads

4

Readme

ng5plus-auth

Angular 5+ authentication service. This service is used with Angular router.

Installation

$ npm install --save ng5plus-auth

Dependencies

Integration

1. app.module.ts

import { AppRoutesModule } from './app-routes.module';
import { CookiesService } from 'ng5plus-cookies';
import { AuthService } from 'ng5plus-auth';

const api_base_url = 'http://localhost:4444/api';

const auth_urls = {
  afterGoodLogin: '/{loggedUserRole}', // {loggedUserRole} -> 'admin' | 'customer'
  afterBadLogin: '/login',
  afterLogout: '/login'
};

const cookie_options = {
  // domain: 'localhost',
  path: '/',
  expires: 3, // expire in 3 days
  // expires: new Date('2018-10-31T03:24:00'),
  secure: false,
  httpOnly: false,
  sameSite: 'strict'
};

@NgModule({
  declarations: [],
  imports: [AppRoutesModule],
  providers: [
    CookiesService,
    AuthService,
    { provide: 'API_BASE_URL', useValue: api_base_url },
    { provide: 'AUTH_URLS', useValue:  auth_urls },
    { provide: 'COOKIE_OPTS', useValue: cookie_options },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Notice: {loggedUserRole} is like variable which is replaced with user's role: admin, customer, ... User's role have to be returned by API.

2. app-routes.module.ts

// modules
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// components
import { HomeComponent } from './pages/home/home.component';
import { LoginComponent } from './pages/login/login.component';
import { AdminComponent } from './pages/admin/admin.component';
import { CustomerComponent } from './pages/customer/customer.component';
import { NotfoundComponent } from './pages/notfound/notfound.component';

// services
import { IsLoggedService, HasRoleService, AutologinService } from 'ng5plus-auth';

// routes
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent, canActivate: [AutologinService] },
  { path: 'admin', component: AdminComponent, canActivate: [IsLoggedService, HasRoleService] },
  { path: 'customer', component: CustomerComponent, canActivate: [IsLoggedService, HasRoleService] },
  { path: '404', component: NotfoundComponent },
  { path: '**', redirectTo: '/404' }
];


@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  providers: [IsLoggedService, HasRoleService, AutologinService],
  exports: [ RouterModule ],
  declarations: [
    HomeComponent,
    AdminComponent,
    CustomerComponent,
    NotfoundComponent
  ]
})

export class AppRoutesModule {}

Methods

login(creds: Credentials): Observable

Login with const creds = {username: 'xxxx', password: 'yyyy'} and redirect to URL defined by auth_urls.afterGoodLogin.

Required 'creds' properties are:

interface Credentials {
  username: string;
  password: string;
}

logout(): void

Logout and re.

getLoggedUserInfo(): LoggedUser

Get logged user info. This object is returned by API and stored into cookie auth_loggedUser.

Required user object properties are:

interface LoggedUser {
  first_name: string;
  last_name: string;
  address?: string;
  city?: string;
  country?: string;

  phone?: string;
  email: string;
  website?: string;

  misc?: any;

  username: string;
  password?: string;

  role: string;
  is_active?: boolean;
  jwt_token?: string;
}

so API response should return those fields.

getJWTtoken(): string

Take JWT token from 'auth_jwtToken' cookie. This token is fetched from API and stored in 'auth_jwtToken' cookie.

API response

In order to work properly this service requires following JSON response or simmilar:

{
    "success": true,
    "message": "Login was successful. JWT is generated and you can use it in API request header. Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVhZjdmYTZmMjlmOWJlMTg1MmRkNjMyZSIsInVzZXJuYW1lIjoiYWRtaW4iLCJpYXQiOjE1Mjc5MzYxNjR9.QI78esEzZkxpkuMhWGqPASGvRvrti1GNWM7ozxnvyfU",
    "jwtToken": "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVhZjdmYTZmMjlmOWJlMTg1MmRkNjMyZSIsInVzZXJuYW1lIjoiYWRtaW4iLCJpYXQiOjE1Mjc5MzYxNjR9.QI78esEzZkxpkuMhWGqPASGvRvrti1GNWM7ozxnvyfU",
    "loggedUser": {
        "role": "admin",
        "is_active": true,
        "_id": "5af7fa6f29f9be1852dd632e",
        "first_name": "Marko",
        "last_name": "Adminić",
        "address": "Radića 23",
        "city": "Osijek",
        "country": "Croatia",
        "phone": "+385-93-2111-222",
        "email": "[email protected]",
        "website": "www.uniapi.org",
        "username": "admin",
        "password": "--removed--",
        "created_at": "2018-05-13T08:42:23.363Z",
        "updated_at": "2018-06-02T10:42:44.175Z",
        "__v": 0,
        "jwt_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVhZjdmYTZmMjlmOWJlMTg1MmRkNjMyZSIsInVzZXJuYW1lIjoiYWRtaW4iLCJpYXQiOjE1Mjc5MzYxNjR9.QI78esEzZkxpkuMhWGqPASGvRvrti1GNWM7ozxnvyfU"
    }
}

Method Implementation

login({username: , password: })

/pages/login/login.html

<form id="login-form" action="#" method="POST" novalidate="" [formGroup]="loginFG">
    <div class="form-group">
        <label for="username">Username</label>
        <input type="text" class="form-control underlined" placeholder="Your username" required formControlName="username"> </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input type="password" class="form-control underlined" placeholder="Your password" required formControlName="password"> </div>
    <div class="form-group">
        <button type="button" class="btn btn-block btn-primary" (click)="login()">Login</button>
    </div>
    <div>
        <p class="alert alert-warning" *ngIf="!!err && !!err.message">{{err.message}}</p>
    </div>
</form>

/pages/login/login.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { AuthService } from 'ng5plus-auth';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  loginFG: FormGroup;
  err: Error;

  constructor(private fb: FormBuilder, private authService: AuthService) { }

  ngOnInit() {
    this.loginFG = this.fb.group({
      username: '',
      password: ''
    });
  }


  login() {
    const creds = this.loginFG.value; // {username: , password: }

    this.authService.login(creds)
      .subscribe((loggedUser: any) => {
        const jwtToken = this.authService.getJWTtoken();
        console.info('LOGGED USER:: ', loggedUser, ' jwtToken=', jwtToken);
      }, (err) => {
        this.err = err.error;
        setTimeout(() => {
          this.err = null;
        }, 2100);
        console.error('ERROR: ', err);
      });
  }

}

logout()

/pages/admin/admin.html

<a class="dropdown-item" [routerLink]="" (click)="logout()"><i class="fa fa-power-off icon"></i> Logout </a>

/pages/admin/admin.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from 'ng5plus-auth';

@Component({
  selector: 'app-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdminComponent implements OnInit {

  loggedUser: any;

  constructor(private authService: AuthService) {
    this.loggedUser = authService.getLoggedUserInfo();
  }

  ngOnInit() {
  }

  logout() {
    console.log('LOGOUT:: ');
    this.authService.logout();
  }

}

Protections

Route Gurads

To protect angular routes from unauthorized access this service uses canActivate route guards:

  • IsLoggedService check if user is logged with valid username:password.
  • HasRoleService check if user has appropriate role, e.g. role must me contained in URL string, for example: /admin/dashboard is valid for 'admin' role but /customer/dashboard is not valid for 'admin' role. This guard must be applied after IsLoggedService guard.
  • AutologinService check if user is already logged. If yes then automatically redirect to URL defined by auth_urls.afterGoodLogin. This guard should be applied only on login page e.g. /login angular route.

API HTTP Request protections

To protect each API request use JWT Token from 'auth_jwtToken' cookie and use it in HTTP header 'Authorization: JWT ' as HTTP interceptor for each API request.

Example

This npm package is integrated in ng5plus-startup so it is full integration example and shows how to use it regularly.

Licence

Created by Saša Mikodanić under MIT licence.