npm package: @hgmap/lbext-auth
Description: Loopback authentication out of the box
Author: MPavlov
Latest version: 2.0.2


# @hgmap/lbext-auth

A Loopback 4 authentication out of the box. Include DataSources,Models,Repositories artifacts.

## Overview

This component contains datasources,models,repositories for speed up your start with an authentication of Loopback 4 application.

## Fast Start

1. `lb4 app-test`
2. `cd app-test/ && npm install --save @hgmap/lbext-auth`
3. `cp node_modules/\@hgmap/lbext-auth/examples/application.ts src/`
4. `cp node_modules/\@hgmap/lbext-auth/examples/sequence.ts src/`
5. `cp node_modules/\@hgmap/lbext-auth/examples/defaultUsers.json ./`
  this database contains all users with password '12345678' (e.g. { login: 'mpavlov02@email.me', password: '12345678' })
6. `npm run start`

Application class name is AppTestApplication by default. You can rename it.


## Usage:

1. `npm install --save @hgmap/lbext-auth`

2. Edit `application.ts` by adding import from this component and activate it by calling `app.component()` method of the application and add component (@hgmap/lbext-auth) configuration.

You can use default artifacts (controllers,models,datasources,repositories) if you don't need any specific features.
```ts
...
    options.lbextAuth = {
      defaultArtifacts: {
        repositories: {
          repoUser: true  // use UserRepository from component; if false then use copy or your own from <projDir>/src/repositories/<UserRepository>.ts
        },
        controllers: {
          auth: true,     // use AuthController from component; if false then use copy or your own from <projDir>/src/controllers/<AuthController>.ts
          user: true,     // use UserController from component; if false then use copy or your own from <projDir>/src/controllers/<UserController>.ts
        },
        datasources: {
          dataUser: true, // use UserDataSource from component; if false then use copy or your own from <projDir>/src/datasources/<UserDataSource>.ts
          // if it's true, you can also reconfigure datasource by it's config only in the UserServiceBindings.DS_CFG variable
        },
      },
    };
...
```
Also you can copy needed files to your project source directory from component sources `node_modules/@hgmap/lbext-auth/src/default-artifacts/<needed part>`

You may want to following some scenarios:
- overwrite config of default datasource (use another connector or destination path of memory data file)
- create your own (or copy default ones to application source directory) datasource(s) and set `defaultArtifacts.datasources.dataUser = false`
- create your own (or copy default ones to application source directory) repositories and set `defaultArtifacts.repositories.repoUser = false` and create your own (or copy default ones to application source directory) model(s) and it's relations
- create your own (or copy default ones to application source directory) controller(s) and set `defaultArtifacts.controllers.<auth or/and user> = false`


3. Edit `sequence.ts` by adding import from this component and insert one line of code that calling of `.AUTH_ACTION` from AuthenticationBindings imported.


User database is in the `process.cwd()+'/defaultUsers.json'` by default. But you can change it by configure (see `#1`)


## That's all

All you need is `@authenticate('jwt')` on every method to be authenticated !




### src/sequence.ts
```ts
...

++ import {
++   AuthenticateFn,
++   AuthenticationBindings,
++ } from '@hgmap/lbext-auth';

...

export class MySequence implements SequenceHandler {
  constructor(

...

++  @inject(AuthenticationBindings.AUTH_ACTION) public authRequest: AuthenticateFn,
  ) {}

  async handle(context: RequestContext) {
    try {
      const {request, response} = context;
      const route = this.findRoute(request);

++    await this.authRequest(request);

      const args = await this.parseParams(request, route);
      const result = await this.invoke(route, args);
      this.send(response, result);
    } catch (err) {
      this.reject(context, err);
    }
  }
}
```

### src/application.ts
```ts
...

++ import {
++   AuthComponent, TokenServiceBindings, PasswordServiceBindings, UserServiceBindings,
++ } from '@hgmap/lbext-auth';

export class ApiCoreApplication extends BootMixin(
  ServiceMixin(RepositoryMixin(RestApplication)),
) {
  constructor(options: ApplicationConfig = {}) {
    super(options);

	...


    // component lbext-auth config

++    options.lbextAuth = {
++      defaultArtifacts: {
++        repositories: {
++          repoUser: true  // use UserRepository from component; if false then use copy or your own from <projDir>/src/repositories/<UserRepository>.ts
++        },
++        controllers: {
++          auth: true,     // use AuthController from component; if false then use copy or your own from <projDir>/src/controllers/<AuthController>.ts
++          user: true,     // use UserController from component; if false then use copy or your own from <projDir>/src/controllers/<UserController>.ts
++        },
++        datasources: {
++          dataUser: true, // use UserDataSource from component; if false then use copy or your own from <projDir>/src/datasources/<UserDataSource>.ts
          // if it's true, you can also reconfigure datasource by it's config only in the UserServiceBindings.DS_CFG variable
++        },
++      },
++    };
++    this.component(AuthComponent);
/**
    configure TokenService (for JWT authentication) and PasswordService (hash settings)
*/
    // default: "ZDUwYTc3OGM4Y2NjOTUwODQ0NTMyNWU3MWJlZmJjOTI3ZWUwNzRmMSAgLQo="
++    this.bind(TokenServiceBindings.SECRET).to('AS SECRET YOU CAN USE RS256 ALG WITH CERTIFICATE');
/**
    you can create and use certificate:
      const private_key = fs.readFileSync('path/to/cert/directory/private.key','utf8'); - for generateToken - as your secret
      const public_key = fs.readFileSync('path/to/cert/directory/public.key','utf8'); - for verifyToken - you can use it on many other servers...
*/
    // default: "LoopbackApp"
++    this.bind(TokenServiceBindings.ISSUER).to('Issuer');
    // default: "Loopback"
++    this.bind(TokenServiceBindings.AUDIENCE).to('Audience');
    // default: "600" NOTE: string
++    this.bind(TokenServiceBindings.EXPIRES_IN).to('600');


    // default: "MzQ5MjBhZGQyYTZhZmJkNzJiZmNlNDc0NGU0OWVhMTg1NDk0YzM4YiAgLQo="
++    this.bind(PasswordServiceBindings.SALT).to('SALT ITS NOT REQUIRED');
    // default: 64 bytes - hash length
++    this.bind(PasswordServiceBindings.LENGTH).to('64');

/**
    if defaultArtifacts.datasources.dataUser is true (also any of available datasources) then you can reconfigure default UserDataSource (overwrite config)
    by binding of datasource config to UserServiceBindings.DS_CFG. See below

 ---
    this.bind(UserServiceBindings.DS_CFG).to({
        "name": "dbusers",
        "connector": "memory",
        "localStorage": "",
        "file": process.cwd()+'/db-users.json',
    });
 ---

    or use your favourite connector...




    if you didn't define datasource User that use the default one from component
    then you need uncomment lines below and copy defaults/create your own datasource.
    As below:

 ---
    this.bind(UserServiceBindings.DS).toClass(UserDataSource);
 ---




    if you didn't define defaultArtifacts.repositories or set defaultArtifacts.repositories.repoUser to false
    then you need copy default to your application src/repositories directory or create your own by lb4/manual
    And bind it to UserServiceBindings.REPO_USER as you can see below:

 ---
    this.bind(UserServiceBindings.REPO_USER).toClass(UserRepository);
 ---

    NOTE: you also need to create User model and UserRelations ...
*/

  }
}
```



### Default login in API explorer (swagger)

Swagger user interface of API explorer is on `localhost:3000/explorer` by default
To be logged in you need go through some steps:

1. Create the first user in the top application directory (the same level of `src/` and `dist/` directories) in the file `defaultUsers.json` or in your database if you use your own...
```js
{
  "ids": {
    "User": 2
  },
  "models": {
    "User": {
      "1": "{\"id\":1,\"firstname\":\"John\",\"lastname\":\"Travolta\",\"username\":\"JT100\",\"email\":\"whatever@email.me\",\"password\":\"rDFsmb5END6nX7denegFLEed7UA3YwEBGQvqNjrdnT9Jk1OrsCAGVM4kh16xt5DCrsxxpT4YF6t3tNSl7hcFSQ==\"}"
    }
  }
}
```
copy and paste above code to this file. Credentials of this new user is `login: whatever@email.me and password: 12345678`.

2. go to `localhost:3000` and press on the `Authorize` button
![step0](docs/img/auth-explorer/step0.png)

3. enter login and password to basic authentication part.
![step1](docs/img/auth-explorer/step1.png)
![step2](docs/img/auth-explorer/step2.png)

4. press on to `/login/basic` method, then press on to `try it out` and press `execute`.
Alternatively, you can insert credentials to request body data of the `/login/json` method...
This actions returns token that needed to authenticate for all other methods.
- press method
![step3](docs/img/auth-explorer/step3.png)
- press `try it out`
![step4](docs/img/auth-explorer/step4.png)
- press `execute`
![step5](docs/img/auth-explorer/step5.png)
- got token
![step6](docs/img/auth-explorer/step6.png)

5. This token need to be pasted to Authorization modal form - JWT part. (press `Authorize` button on the top of the page)
![step7](docs/img/auth-explorer/step7.png)

Now, You can do all of actions following 10 minutes (600 sec by default). Enjoy )