Loopback-next: Only one strategy allowed in Authentication

Created on 10 Dec 2018  路  11Comments  路  Source: strongloop/loopback-next

Description / Steps to reproduce / Feature proposal

Hi, I'm new to loopback, before opening this issue I tried to find a solution in the issues list or in the google discussion but without success, so here I am.

I'm trying to implement a basic use case for authentication. My scenario is:

  1. client performs a call to /login endpoint passing username and password via a basic http authentication
  2. /login endpoint is decorated with @authenticate('BasicStrategy') so credentials are checked and, if they are ok, the endpoint creates and returns a JWT to the client
  3. client performs a call to /todos/count endpoint sending the JWT in the Auth header (bearer token)
  4. /todos/countis decorated with @authenticate('JwtStrategy') so the JWT token is verified and, if it is ok, the endpoint give back the result to the client

Current Behavior

Everything goes fine until step 4. where I get the error:

Unhandled error in GET /todos/count: 500 The strategy JwtStrategy is not available.

The root cause is in application.ts, where I bind the two strategies for authentication:

    this.bind(AuthenticationBindings.STRATEGY).toProvider(
      JwtAuthStrategyProvider,
    );
    this.bind(AuthenticationBindings.STRATEGY).toProvider(
      BasicHTTPAuthStrategyProvider);

and, as it is clearly stated in the documentation, only one bind is allowed for the same key.

So it seems that the current design of Authentication would not allow more than one strategy at the same time.

For this simple use case it would not be a problem (it is as simple as removing BasicStrategy, because it is used in /login endpoint only and it could be implemented in many different ways).

But what about real production scenarios where multiple strategies should be supported?

Expected Behaviour

In a real, complex project, more than one authentication strategy is often a requirement so IMO it should be supported.

Authentication

Most helpful comment

@Swati-GOT, did you get a chance to look at the sample snippet in https://loopback.io/doc/en/lb4/Authentication-component-decorator.html#authentication-decorator?

  @authenticate({
    strategy: strategyName1,
    options: {option1: 'value1'}
  }, {
    strategy: strategyName2,
    options: {option2: 'value2'}
  })

All 11 comments

@jannyHou , could you please take a look? I think it's related to the authentication work that you're doing. Thanks.

Hello @sertal70 ,

I am newbie into LB4 , so apologies if I am talking out of senses ( hehe ).

the below solution could be a workaround, i guess ( i have not tried though),

Let there be a CommonAuthStrategyProviderClass. Assign this Class to the AuthenticationBindings.STRATEGY Key, and then use this:

if (name === 'BasicStrategy') {
      let self = this;
      return new BasicStrategy(this.basicVerify.bind(self));
    } else if (name === 'JWTStrategy') {
      return new JWTStrategy({
        secretOrKey: this.configuration.secrets.jwtSecret,
        jwtFromRequest: ExtractJwt.fromHeader('SOME_HEADER_NAME') // Here extract from headers
      }, this.verifyCallback);
    }

Or Call two separate Auth-Component classes from each of 'if' statements ?

My thought process was: We donot specifiy the Exact Strategy in AuthProviderClass declaration and only create instance when we are sure of what kind of strategy has been decorated on the controller. So insead of exposing multiple auth provider controllers(each specific to one strategy), we can have our MainAuthController which can route/decide on the response.

Please correct me If i misunderstood something.

Hello @rohit-khanna, thanks for your suggestion and... welcome to the team of LB4 newbie! :)

Theoretically it should work as workaround, I'll give it a try (as soon as I have time) to verify that works and, more important, that there are no side-effects.

@sertal70 , glad to be welcomed in the growing team :)
I gave the above solution a shot and it did worked.

I had two endpoints in my controller , one with 'Basic Strategy' and Other one with 'JwtStrategy'. And with the above code i was able to achieve this.

And yes, whenever you have time, you can share your views, this will help us grow..

Cheers :)

@rohit-khanna I implemented your solution and I can confirm it works, so at least it seems to be a viable workaround until the LB4 team will decide to support more that one auth strategy using the default binding mechanism. Which, IMHO, it should be the preferred way because there is no need to write&mantain a custom auth provider.

@sertal70 @rohit-khanna The team realized the authentication system should be extensible, story
https://github.com/strongloop/loopback-next/issues/2312
and
https://github.com/strongloop/loopback-next/issues/2311
are created for allowing people plugin more auth strategies.
Those two stories are our high priorities now.

@jannyHou Thats Great. Looking forward to them ! :)
@sertal70 thanks for validation of my workaround :)

@jannyHou very good news, thanks!

@rohit-khanna thanks to you for the suggestion!

This feature is supported after having the extension point :)
See the new Authentication component
Especially Registering Custom Auth Strategy

@rohit-khanna It would be great if can u please provide us with some code snippet for this example.
I want to achieve the same thing but somehow I m not able to implement this example.
Will be very thankful you can help me asap

@Swati-GOT, did you get a chance to look at the sample snippet in https://loopback.io/doc/en/lb4/Authentication-component-decorator.html#authentication-decorator?

  @authenticate({
    strategy: strategyName1,
    options: {option1: 'value1'}
  }, {
    strategy: strategyName2,
    options: {option2: 'value2'}
  })
Was this page helpful?
0 / 5 - 0 ratings