feathers icon indicating copy to clipboard operation
feathers copied to clipboard

Custom auth strategy

Open PowerMogli opened this issue 6 years ago • 13 comments

We are trying to migrate to v4. But now we are failing because we have no clue how to setup a custom auth (api-key) strategy. In v3 we registered our custom api-key strategy at passport like this:

this.passport.use('apikey', new Strategy(verifier));
// and
app.configure(apikey({ header: config.apiKey.header }));

Is there any documentation how to setup a custom (api-key) authentication strategy?

PowerMogli avatar Sep 09 '19 14:09 PowerMogli

Hi, custom apiKey strategy is only thing I have successfully set up after migrating to v4. Oauth still not working for me.

authentication.js

const { LocalStrategy } = require('@feathersjs/authentication-local');
const { expressOauth } = require('@feathersjs/authentication-oauth');
const { NotAuthenticated } = require('@feathersjs/errors');

class ApiKeyStrategy extends AuthenticationBaseStrategy {
  constructor (headerField = 'x-api-key') {
    super();
    this.headerField = headerField;
  }

  authenticate(authRequest, params) {
    const { apiKey } = authRequest;

    const match = this.app.get('allowed-tokens').includes(apiKey);
    
    if (!match) {
      throw new NotAuthenticated('Invalid API key');
    }
    
    // To add a user look it up from the service
    // const [ user ] = await this.app.service('users').get({ ...params, query: userQuery })
    
    return {
      apiKey: true
      // user
    };
  }
  
  parse (req) {
    const header = req.headers[this.headerField];
    
    if (header) {
      return {
        strategy: this.name,
        apiKey: header
      };
    }
    
    return null;
  }
}

module.exports = app => {
  const authentication = new AuthenticationService(app);

  authentication.register('jwt', new JWTStrategy());
  authentication.register('local', new LocalStrategy());
  authentication.register('apiKey', new ApiKeyStrategy());

  app.use('/authentication', authentication);
  app.configure(expressOauth());
};```

./hooks/allowApiKey.js

/* eslint-disable require-atomic-updates */ module.exports = function (options = {}) { // eslint-disable-line no-unused-vars return async context => { const { params } = context;

  if(params.provider && !params.authentication && params.headers && params.headers['x-api-key']) {
    
    context.params = {
      ...params,
      authentication: {
        strategy: 'apiKey',
        apiKey: params.headers['x-api-key']
      }
    }
  }
  return context;
};

};

 
Now in every service you want to access with this strategy you must add this hook and auth..
/services/users/users.hook.js

```const allowApiKey = require('../../hooks/allowApiKey');

module.exports = {
  before: {
    all: [ allowApiKey(), authenticate('jwt', 'apiKey') ],
...```

ivankostic85 avatar Sep 14 '19 22:09 ivankostic85

In my example header key is "x-api-key" and I have array of tokens in config called allowed-tokens and this part const match = this.app.get('allowed-tokens').includes(apiKey); can be simple const match = apiKey === 'yourxxxsecret'

Hope I help you and if you have working oauth google and facebook strategies, please help me :)

ivankostic85 avatar Sep 14 '19 22:09 ivankostic85

Hope I help you and if you have working oauth google and facebook strategies, please help me :)

Facebook: https://docs.feathersjs.com/cookbook/authentication/facebook.html Google (not yet merged): https://github.com/feathersjs/docs/blob/495f82121ee22a5eca1f82bfa64c5c8e2bc1e518/cookbook/authentication/google.md

bartduisters avatar Sep 16 '19 18:09 bartduisters

Thanks @bartduisters I have managed to solve issues with Google and Facebook providers. In your Google cookbook example there are no getProfil method. I can send you my if you want to checkout

ivankostic85 avatar Sep 16 '19 19:09 ivankostic85

The .getProfile() method is not necessary if all the information you want is the information used in the recipe.

I think the issue can be closed since the OP has an answer + you have an answer.

bartduisters avatar Sep 16 '19 19:09 bartduisters

This seems to be working for me, but haven't fully tested yet (thanks)... now I just need to figure out how to add a custom Verifier for local....

In V3: app.configure(local({ Verifier: CustomVerifier })) and adding it in V4 here: authentication.register('local', new LocalStrategy({ Verifier: CustomVerifier })) doesn't work :(

MarcGodard avatar Oct 06 '19 01:10 MarcGodard

There are no more verifiers in v4. Strategies are now customized by extending them as is documented in

daffl avatar Oct 06 '19 02:10 daffl

Hi, I'm new to the whole feathers world. I really like the approach you guys are taking :) Is there any way of doing custom authentication? Let's say for example I want to have a custom jwt secret for each user. What would be the approach you'd recommend?

cupcakearmy avatar Oct 24 '19 12:10 cupcakearmy

@cupcakearmy See this: https://github.com/feathersjs/feathers/issues/1601

MarcGodard avatar Oct 24 '19 15:10 MarcGodard

Hey @PowerMogli ,

try this one https://www.npmjs.com/package/@thesinding/authentication-api-key

Cheers!

dmitry-tuzenkov avatar Jan 27 '20 20:01 dmitry-tuzenkov

In the AuthenticationBaseStrategy that @ikakosta posted, does it use the parse method at all? I implemented it and it seems that method is never called... (only the hook matters).

Just curious. @daffl the docs here https://docs.feathersjs.com/api/authentication/strategy.html#parse-req-res aren't super clear on when parse is ever called / other usage patterns.

jiangts avatar Apr 28 '20 17:04 jiangts

Can probably be improved by pointing to the parseStrategies and authStrategies configuration option where the name of the strategy you want to use has to be added.

daffl avatar Apr 28 '20 17:04 daffl

Yep! I just figured it out. It just needs to be added to the authStrategies config! Probably the anonymous auth guide should also be updated to add "anonymous" to authStrategies rather than using a hook...

Thanks for the fast reply!!

jiangts avatar Apr 28 '20 17:04 jiangts