Hello Peppos!!
Today we are going to add Authentication to the Todo App that we previously made to make the application’s API more secure.
LoopBack4 has a Authentication package with the name of @loopback/authentication
in which secures your app’s API’s endpoints with custom authentication strategies and an @authenticate
decorator.
This tutorial is based on the tutorial on the LoopBack4 Website.
Take a look on the final project if you have any problems or errors in the making of this tutorial.
JSON Web Token Approach
In this authentication method, when the user provide the credentials to a login endpoint, the server creates a JWT token and returns it as a response (upper part). That token is a string that consists of 3 parts:
- A Header
- A Payload
- A Signature
The header and the payload are signed with secret and the parts are separated by a period
After logging in, when the user attemps to access a protected endpoint, the token must be used in the Authorization header. The server verifies if the token is valid, and allows access to the protected endpoint.
To install the authentication package on the project just run the command:
npm i --save @loopback/authentication @loopback/authentication-jwt
Bind JWT Component in the Application
To bind the authentication component, add the following code to src/application.ts
:
// ---------- ADD IMPORTS -------------
import {AuthenticationComponent} from '@loopback/authentication';
import {
JWTAuthenticationComponent,
SECURITY_SCHEME_SPEC,
UserServiceBindings,
} from '@loopback/authentication-jwt';
import {DbDataSource} from './datasources';
// ------------------------------------
export class TodoListApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options: ApplicationConfig = {}) {
//...
// ------ ADD SNIPPET AT THE BOTTOM ---------
// Mount authentication system
this.component(AuthenticationComponent);
// Mount jwt component
this.component(JWTAuthenticationComponent);
// Bind datasource
this.dataSource(DbDataSource, UserServiceBindings.DATASOURCE_NAME);
// ------------- END OF SNIPPET -------------
}
}
Create the UserController for login
In the UserController, we are going to create3 endpoints:
/login
for users to provide credentials./signup
for users to sign up./whoami
for showing who the user currently is.
Create the controller using lb4 controller
command with the empty controller option.
$ lb4 controller
? Controller class name: User
Controller User will be created in src/controllers/user.controller.ts
? What kind of controller would you like to generate? Empty Controller
create src/controllers/user.controller.ts
update src/controllers/index.ts
Controller User was created in src/controllers/
Add endpoints in UserController
For UserService which verifies the credentials, we are going to use the default implementation in @loopback/authentication-jwt
. Therefore, the constructor injects the MyUserService
from this extension.
The controller’s location is in /src/controllers/user.controller.ts.
// ---------- ADD IMPORTS -------------
import {inject} from '@loopback/core';
import {
TokenServiceBindings,
MyUserService,
UserServiceBindings,
UserRepository,
} from '@loopback/authentication-jwt';
import {TokenService} from '@loopback/authentication';
import {SecurityBindings, UserProfile} from '@loopback/security';
import {repository} from '@loopback/repository';
// ----------------------------------
constructor(
@inject(TokenServiceBindings.TOKEN_SERVICE)
public jwtService: TokenService,
@inject(UserServiceBindings.USER_SERVICE)
public userService: MyUserService,
@inject(SecurityBindings.USER, {optional: true})
public user: UserProfile,
@repository(UserRepository) protected userRepository: UserRepository,
) {}
Now you can implement yourself the 3 endpoints, or you can scroll down to the end of this tutorial to see the final result of user.controller.ts
.
Protect the Todo API’s
To protect other endpoints that we have. Go to src/controllers/todo.controller.ts
and imply add @authenticate('jwt')
before the TodoController
class.
// ---------- ADD IMPORTS -------------
import {authenticate} from '@loopback/authentication';
// ------------------------------------
@authenticate('jwt') // <---- Apply the @authenticate decorator at the class level
export class TodoController {
//...
}
If there are particular API that you want to make it available to everyone without authentication, you can add @authenticate.skip()
before that function.