2JN
2JN

Reputation: 653

Optional authentication service

TL;DR The problem is how to get the the user information from a jwt

I'm trying to get the information of a user from the jwt if one is sent on the request but I don't want to close the endpoint to only logged in users.

I don't want to close the endpoint with the authenticate hook but I don't know how to get the user information without it.

I'm using a local strategy with jwt.

Upvotes: 1

Views: 775

Answers (4)

2JN
2JN

Reputation: 653

This is the only method it worked for me.

const { iff } = require('feathers-hooks-common');
const { authenticate } = require('@feathersjs/authentication').hooks;

module.exports = {
    before: {
        all: [iff(
            (({ params: { headers: { authorization }}}) => authorization),
            authenticate('jwt')
        )],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
    },

    after: {
        all: [],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
    },

    error: {
        all: [],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
    }
};

I just verified that the authorization token was sent.

Upvotes: 0

Andrinux
Andrinux

Reputation: 374

The method with "try/catch" is good, but there is another way based on hooks.

1) Create custom hooks isAuth.js:

module.exports = (context) => {
  return !!(context.params.headers.authorization
    && context.params.headers.authorization !== 'null'
    && context.params.headers.authorization !== '');
};

2) Fix the service hooks.js(app.service('/my-url').hooks(hooks)) in which method authorization will be optional. NOTE: if the user is not authorized, then in "params.user" object "user" will be absent.

const { iff } = require('feathers-hooks-common');
const { authenticate } = require('@feathersjs/authentication').hooks;
const isAuth = require('isAuth');

module.exports = {
  before: {
    find: [iff(isAuth, authenticate('jwt'))],
  },
  after: {}
};

Upvotes: 1

Joe
Joe

Reputation: 42627

You can also do a try/catch around the authenticate hook to attempt to authenticate a route but not fail because of it e.g.

const tryAuth = async hook => {
  try {
    return await authenticate(hook); 
  } catch(err) {
    // do nothing?
    return hook;
  }
};

in which case, if there was a valid token, you'll have params.user and authenticated = true otherwise not.

Upvotes: 0

Daff
Daff

Reputation: 44215

Even if you don't use the authentication hook, the authentication information of the request (if any) will be available in params.authentication. You can do whatever you want with it in your own hook:

module.exports = () => async context => {
  const { authentication } = context.params;
  // authentication will e.g. be { strategy: 'jwt', accessToken }

  // do whatever you like here including throwing errors
}

To get the user information or allow anonymous access see the Anonymous Authentication cookbook recipe.

Upvotes: 1

Related Questions