Skip to content
This repository has been archived by the owner on Mar 22, 2022. It is now read-only.

Customize the JWT payload #78

Closed
enten opened this issue Feb 24, 2016 · 9 comments
Closed

Customize the JWT payload #78

enten opened this issue Feb 24, 2016 · 9 comments
Milestone

Comments

@enten
Copy link
Contributor

enten commented Feb 24, 2016

Is it possible to customize the JWT payload?
After code review, I thinks that the answer is no. But I want to be sure.

What do you think about a new configuration option named userPayload which may be used to customize the JWT payload?

userPayload can be an array which contains extra field names to put in payload (next to idField).

To implement that feature, we should factorize the code below (existing into services/local/index.js and services/oauth/index.js) into a new createPayload function which accept user, idField and extraFields (corresponding to new userPayload).

        // replace...
        const payload = {
          id: user.id !== undefined ? user.id : user._id
        };
        // by...
        const payload = createPayload(user, this.options.idField, this.options.userPayload);

Implementation example of createPayload:

function createPayload(user, idField, extraFields) {
  let payload = {
    id: user[idField] || user.id || user._id
  };

  if (!payload.id) {
    // throw error
  }

  if (Array.isArray(extraFields)) {
    extraFields.forEach(fieldName => payload[fieldName] = user[fieldName]);
  }

  return payload;
}

Do you find that feature useful?
The main purpose is to have user data without requesting the database (doesn't need to call populateUser hook for few user data).

@ekryski
Copy link
Member

ekryski commented Feb 24, 2016

@enten I'm definitely open to it. We actually started down the route of just encoding the whole user in the JWT payload but we found that the JWT could get massive if you aren't selecting specific fields. I think your solution is great so if you want to put together a PR that would be awesome!

Things to do:

  • Implement createPayload()
  • Test token encryption with all potential options
  • Document new idField and extraFields authentication options
  • Issue minor release

We'll need to make sure it has a test. I'll be backfilling other tests today so I could help with that.

@enten
Copy link
Contributor Author

enten commented Feb 24, 2016

I'm glad you like the idea.
I'm working on my fork to prepare a PR for that.

  • Implement createPayload()

After another code review, I prefer another solution due to the file organization: I don't want to create more file dependency for only one function (and I don't know where creates this new dependency).

I suggest to update the token.create method to create(user): because we create a token based on an user (so it's the input).

And we create the payload in token.create before signing it.

What do you think about this modification?

  • Test token encryption with all potential options

What do you mean by "potential options"? idField and extraFields?

  • Document new idField and extraFields authentication options

The idField option already exists?
I found it in authentication doc.
I believe that its integration is incomplete (see TODO marker here and there)

I suggest extraFields not for the option name but for the param name of the eventual createPayload function. I suggest userPayload for the option name (it's coherent with the related option userEndpoint).

We'll need to make sure it has a test

I'll be happy if I do not break the existing tests. I will need your help for that.

@ekryski ekryski modified the milestone: 1.0 release Mar 19, 2016
@ekryski
Copy link
Member

ekryski commented Mar 24, 2016

Closed in v0.6.0 by #109. In order to customize the JWT payload you can do this:

app.configure(authentication({
  token: {
    payload: ['email', 'name'],
  }
}));

@ekryski ekryski closed this as completed Mar 24, 2016
@ekryski ekryski modified the milestones: 1.0, 0.6 Mar 26, 2016
@crobinson42
Copy link

@ekryski Is there a solution in version 2.1 for adding custom data to the JWT payload?

ie: querying multiple services to gather needed information for the JWT payload before it's issued

@marshallswain
Copy link
Member

@CrisLi
Copy link

CrisLi commented Jan 24, 2018

@marshallswain How can add some payloads which come from the query result.

Just like

token: {
    payload: ['email', 'name', 'roles'],
 }

@CrisLi
Copy link

CrisLi commented Jan 24, 2018

Got it

add before hooks

  before: {
    create: [
      auth.hooks.authenticate(['local']),
      (context) => {
        const { params, params: { user = {} } } = context;
        params.payload = {
          id: user['_id'],
          username: user.username,
          org: user.org,
          roles: user.roles
        };
      }
    ]
  }

@RickEyre
Copy link

RickEyre commented Mar 1, 2018

@CrisLi I've done a similar thing in your example, but that's causing my JWT to have the incorrect signature for some reason. Not sure what I'm doing wrong.

@CrisLi
Copy link

CrisLi commented Mar 5, 2018

@RickEyre try to look at my code, it is working fine for me.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants