4

My Feathers application needs to be able to have two JWT authentication strategies. For the users service, I need to have, for example, all: [authenticate('carrier')] instead of all: [authenticate('jwt')] in my hooks. For the rest of the services, authenticate['jwt'] is needed.

For this, I have registered a custom strategy in authentication.js called CarrierStrategy as following:

module.exports = function auth(app) {
  const authentication = new AuthenticationService(app)

  // register all of the strategies with authentication service
  authentication.register('carrier', new CarrierStrategy())
  authentication.register('jwt', new JWTStrategy())

  // register the authentication service with your app
  app.use('/api/authentication', authentication)
}

In config/default.json, I have also registered this strategy as following:

authStrategies: ["carrier", "jwt"]

The CarrierStrategy needs to handle the incoming Authorization header a little differently with some custom logic.

When I use Postman to send requests for this service, i.e., localhost:3030/users with a JWT token in the header, I get the following error.

Invalid authentication information (strategy not allowed in authStrategies)'

Please guide me if this is the right way to add a custom strategy to the application.

Kashif Nazar
  • 20,775
  • 5
  • 29
  • 46
  • How does the CarrierStrategy look like? Did you implement the `parse` method (https://docs.feathersjs.com/api/authentication/service.html#parse-req-res-strategies) that does the header parsing? It should return the the `params.authentication` value that can be used by a strategies `authenticate` call. E.g. `parse` for the JWT strategy returns `{ strategy: 'jwt', accessToken: }`. – Daff Jan 28 '20 at 05:26
  • I only implemented the `authenticate` method to see if the control ever reaches here. I can try to add the parse method. – Kashif Nazar Jan 28 '20 at 10:58
  • @Daff - For experiment purposes, I made `CarrierStrategy` extend `JWTStrategy`, but I am still getting the same error. – Kashif Nazar Jan 28 '20 at 18:03

1 Answers1

2

I had a similar problem to this. I wanted both Stateful and Stateless JWT authentication. The problem being that if you just do this in authentication.js

authentication.register('jwt', new JWTStrategy());
authentication.register('jwt-stateless', new JWTStrategy());

Then when you submit a request with a JWT token it will match on either one and you'll end up with a problem in one of your services somewhere.

I ended up creating a custom strategy like this in authentication.js:

class StatelessJWTStrategy extends JWTStrategy {
  get configuration () {
    const authConfig = this.authentication.configuration;
    const config = super.configuration;

    return {
      ...config,
      entity: authConfig.entity,
      service: authConfig.service,
      header: 'Authorization',
      schemes: [ 'STATELESS' ]
    };
  }
}

which is basically a slightly modified JWTStrategy that uses STATELESS in the Authorization header instead of Bearer or JWT. It's not a great solution, but it works.

Then I did this also in authentication.js

authentication.register('jwt', new JWTStrategy());
authentication.register('jwt-stateless', new StatelessJWTStrategy());

Then you need to modify your config.json file. In the authentication section add this:

"jwt-stateless": {
  "entity": null
},
"jwt": {
  "entity": "user",
  "service": "users"
},
"entity": "user",
"service": "users",
"authStrategies": [
  "jwt-stateless",
  "jwt",
  "local"
],

Now you should be able to use the jwt-stateless auth mechanism in your hooks like this:

authenticate('jwt-stateless')

Head over to here to create your stateless JWT. Fill in iss with the issuer and aud with audience details from your config.json, and add a user ID to the sub field. Pop your secret from config.json in the bottom signature verification field and the token on the left should authenticate.

Gerrit
  • 21
  • 1
  • 4