diff --git a/docs/site/tutorials/authentication/Authentication-Tutorial.md b/docs/site/tutorials/authentication/Authentication-Tutorial.md index 6f23f3eddebd..f77b6046f3c9 100644 --- a/docs/site/tutorials/authentication/Authentication-Tutorial.md +++ b/docs/site/tutorials/authentication/Authentication-Tutorial.md @@ -86,13 +86,12 @@ application, follow these steps: 1. In the `UserController` section, click on `POST /users`, click on `'Try it out'`, specify: - ```ts + ```json { - "id": "1", - "email": "user1@example.com", - "password": "thel0ngp@55w0rd", - "firstName": "User", - "lastName": "One" + "email": "user1@example.com", + "password": "thel0ngp@55w0rd", + "firstName": "User", + "lastName": "One" } ``` @@ -101,9 +100,9 @@ application, follow these steps: 1. In the `UserController` section, click on `POST /users/login`, click on `'Try it out'`, specify: - ```ts + ```json { - "email": "user1@example.com", + "email": "user1@example.com", "password": "thel0ngp@55w0rd" } ``` @@ -114,7 +113,7 @@ application, follow these steps: For example: - ```ts + ```json { "token": "some.token.value" } @@ -161,10 +160,11 @@ application, follow these steps: [HTTP 401 UnAuthorized](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) is thrown. - The response is: + The response contains a unique value in the `id` field (generated by the + database) and `name` field with the full user name: - ```sh - {"id":"1","name":"User One"} + ```json + {"id": "5dd6acee242760334f6aef65", "name": "User One"} ``` ## Adding JWT Authentication to a LoopBack 4 Application @@ -193,9 +193,7 @@ so it is important to add the component in the `ShoppingApplication` class in [loopback4-example-shopping/packages/shopping/src/application.ts](https://github.com/strongloop/loopback4-example-shopping/blob/master/packages/shopping/src/application.ts). ```ts -import { - AuthenticationComponent -} from '@loopback/authentication'; +import {AuthenticationComponent} from '@loopback/authentication'; export class ShoppingApplication extends BootMixin( ServiceMixin(RepositoryMixin(RestApplication)), @@ -209,6 +207,9 @@ export class ShoppingApplication extends BootMixin( this.component(AuthenticationComponent); // ... + } + // ... +} ``` ### Securing an Endpoint with the Authentication Decorator @@ -768,6 +769,27 @@ In the `UserController` class in the users can be added by performing a `POST` request to the `/users` endpoint which is handled by the `create()` function. +Because user credentials like password are stored outside of the main user +profile, we need to create a new model (a +[Data Transfer Object](https://en.wikipedia.org/wiki/Data_transfer_object)) to +describe data required to create a new user. The class inherits from `User` +model to include all user profile properties, and adds a new property `password` +allowing clients to specify the password too. + +```ts +@model() +export class NewUserRequest extends User { + @property({ + type: 'string', + required: true, + }) + password: string; +} +``` + +The controller method `UserController.create` then has to remove additional +properties like `password` before passing the data to Repository (and database). + ```ts export class UserController { constructor( @@ -784,16 +806,35 @@ export class UserController { // ... @post('/users') - async create(@requestBody() user: User): Promise { + async create( + @requestBody({ + content: { + 'application/json': { + schema: getModelSchemaRef(NewUserRequest, { + title: 'NewUser', + }), + }, + }, + }) + newUserRequest: NewUserRequest, + ): Promise { // ensure a valid email value and password value - validateCredentials(_.pick(user, ['email', 'password'])); + validateCredentials(_.pick(newUserRequest, ['email', 'password'])); // encrypt the password - user.password = await this.passwordHasher.hashPassword(user.password); + const password = await this.passwordHasher.hashPassword( + newUserRequest.password, + ); // create the new user - const savedUser = await this.userRepository.create(user); - delete savedUser.password; + const savedUser = await this.userRepository.create( + _.omit(newUserRequest, 'password'), + ); + + // set the password + await this.userRepository + .userCredentials(savedUser.id) + .create({password}); return savedUser; }