Search code examples
bindingbindloopbackjsloopback4

Loopback 4 binding USER_SERVICE with a custom user service


I am trying to use my custom MyUserService which implement UserService<MyUser, MyCredentials>:

export class MyUserService implements UserService<Account, LoginCredential> { ... }

The difference from loopback's User, and Credentials are:

  • MyUser.id is a number (while loopback's User.id is a string)
  • MyCredentials has properties: identity and secret (while loopback's Credentials has properties: email and secret)
  • MyUser.credential is the relationship (instead of loopback's User.userCredentials)

The issue is, when I am trying to bind (in application.ts) with:

this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService);

it would not work due to:

Argument of type 'typeof MyUserService' is not assignable to parameter of type 'Constructor<UserService<User, Credentials>>'.
  Types of construct signatures are incompatible.
    Type 'new (myUserRepository: MyUserRepository, passwordHasher: PasswordHasher<string>) => MyUserService' is not assignable to type 'new (...args: any[]) => UserService<User, Credentials>'.
      Construct signature return types 'MyUserService' and 'UserService<User, Credentials>' are incompatible.
        The types of 'verifyCredentials' are incompatible between these types.
          Type '(myCredentials: MyCredentials) => Promise<MyUser>' is not assignable to type '(credentials: Credentials) => Promise<User>'.
            Types of parameters 'myCredentials' and 'credentials' are incompatible.
              Property 'identity' is missing in type 'Credentials' but required in type 'MyCredentials'.ts(2345)
myuser.repository.ts(8, 3): 'identity' is declared here.

In other words, it does not let me bind my custom UserService, unless I follow these rules:

  • the property of the credential in user has to be exactly userCredentials
  • the credential has to have an email and password property
  • the user's ID has to be in a string type
  • ...etc (probably missed much more constraints)

My question is:

How can I bind my custom user service, where I can customize what data is stored in the credentials?


Solution

  • The issue was more simple than I thought. Long story short:

    Simply make sure that I am importing my own UserServiceBindings and not Loopback's default UserServiceBindings.


    In my case, my UserServiceBindings in application.ts was the following:

    import {UserServiceBindings} from '@loopback/authentication-jwt';
    

    which imports the Loopback's default UserServiceBindings, which cause the issue. By replacing the import with a new import to mine UserServiceBindings:

    import {UserServiceBindings} from './mybindings';
    

    have solved the issue.