import { authenticate , TokenService , UserService , } from '@loopback/authentication' ; import { inject } from '@loopback/core' ; import { model , property } from '@loopback/repository' ; import { get , post , requestBody , SchemaObject } from '@loopback/rest' ; import { SecurityBindings , securityId , UserProfile } from '@loopback/security' ; import { genSalt , hash } from 'bcryptjs' ; import { RefreshTokenServiceBindings , TokenObject , TokenServiceBindings , User , UserServiceBindings , } from '../../../' ; import { UserRepository } from '../../../repositories' ; import { Credentials } from '../../../services/user.service' ; import { RefreshTokenService } from '../../../types' ; type RefreshGrant = { refreshToken : string ; } ; const RefreshGrantSchema = { type : 'object' , required : [ 'refreshToken' ] , properties : { refreshToken : { type : 'string' , } , } , } ; const RefreshGrantRequestBody = { description : 'Reissuing Acess Token' , required : true , content : { 'application/json' : { schema : RefreshGrantSchema } , } , } ; const CredentialsSchema = { type : 'object' , required : [ 'email' , 'password' ] , properties : { email : { type : 'string' , format : 'email' , } , password : { type : 'string' , minLength : 8 , } , } , } ; @ model ( ) export class NewUserRequest extends User { @ property ( { type : 'string' , required : true , } ) password : string ; } export const CredentialsRequestBody = { description : 'The input of login function' , required : true , content : { 'application/json' : { schema : CredentialsSchema } , } , } ; export class UserController { constructor ( @ inject ( TokenServiceBindings . TOKEN_SERVICE ) public jwtService , @ inject ( UserServiceBindings . USER_SERVICE ) public userService , @ inject ( SecurityBindings . USER , { optional : true } ) private user , @ inject ( UserServiceBindings . USER_REPOSITORY ) public userRepository , @ inject ( RefreshTokenServiceBindings . REFRESH_TOKEN_SERVICE ) public refreshService ) { } @ post ( '/users/signup' , { responses : { '200' : { description : 'User model instance' , content : { 'application/json' : { schema : { 'x-ts-type' : User , } , } , } , } , } , } ) async signUp ( @ requestBody ( { content : { 'application/json' : { schema : CredentialsSchema , } , } , } ) newUserRequest ) { const password = await hash ( newUserRequest . password , await genSalt ( ) ) ; delete ( newUserRequest as Partial < NewUserRequest > ) . password ; const savedUser = await this . userRepository . create ( newUserRequest ) ; await this . userRepository . userCredentials ( savedUser . id ) . create ( { password } ) ; return savedUser ; } param credentials @ post ( '/users/login' , { responses : { '200' : { description : 'Token' , content : { 'application/json' : { schema : { type : 'object' , properties : { token : { type : 'string' , } , } , } , } , } , } , } , } ) async login ( @ requestBody ( CredentialsRequestBody ) credentials ) { const user = await this . userService . verifyCredentials ( credentials ) ; const userProfile = this . userService . convertToUserProfile ( user ) ; const token = await this . jwtService . generateToken ( userProfile ) ; return { token } ; } @ authenticate ( 'jwt' ) @ get ( '/whoAmI' , { responses : { '200' : { description : '' , schema : { type : 'string' , } , } , } , } ) async whoAmI ( ) { return this . user [ securityId ] ; } param credentials @ post ( '/users/refresh-login' , { responses : { '200' : { description : 'Token' , content : { 'application/json' : { schema : { type : 'object' , properties : { accessToken : { type : 'string' , } , refreshToken : { type : 'string' , } , } , } , } , } , } , } , } ) async refreshLogin ( @ requestBody ( CredentialsRequestBody ) credentials ) { const user = await this . userService . verifyCredentials ( credentials ) ; const userProfile = this . userService . convertToUserProfile ( user ) ; const accessToken = await this . jwtService . generateToken ( userProfile ) ; const tokens = await this . refreshService . generateToken ( userProfile , accessToken ) ; return tokens ; } @ post ( '/refresh' , { responses : { '200' : { description : 'Token' , content : { 'application/json' : { schema : { type : 'object' , properties : { accessToken : { type : 'object' , } , } , } , } , } , } , } , } ) async refresh ( @ requestBody ( RefreshGrantRequestBody ) refreshGrant ) { return this . refreshService . refreshToken ( refreshGrant . refreshToken ) ; } }