express-jwt icon indicating copy to clipboard operation
express-jwt copied to clipboard

Multiple tokens

Open papigers opened this issue 8 years ago • 8 comments

Hi, I'm currently using express-jwt as follows:

app.use(expressJwt({
  secret: config.jwtSecret,
  credentialsRequired: false,
  getToken: req => req.cookies.id_token,
}));

I'm using it currently for authentication purposes only: identifying the user. I also want a second token for authorization, with a lower TTL, so a user would have to be authorized more frequently.

How can I offer another token to be extracted to a different property (say, req.roles).

Is what I need makes sense? Is there a better way to achieve what I want? How can this be done using express-jwt? Thanks!

papigers avatar Jul 14 '17 16:07 papigers

@papigers did you find a solution?

xdeq avatar Dec 31 '17 12:12 xdeq

You can chain multiple instances of jwt: app.use(jwt(authConfig), jwt(anotherConfig));

For anotherConfig you definitely need to use the getToken(https://github.com/auth0/express-jwt#customizing-token-location) to read the second token from somewhere else, and the requestProperty option (https://github.com/auth0/express-jwt#retrieving-the-decoded-payload) to write it to another property.

Narretz avatar Jun 11 '20 15:06 Narretz

@Narretz the chaining as you described doesn't seem to work, it always just picks the first one? and the second doesn't work?

using it like:

app.use(jwt(JWT_STATION_AUTH), jwt(JWT_USER_AUTH))

JClackett avatar Aug 12 '20 13:08 JClackett

@JClackett hard to say why it doesn't work for you. Are you sure you are using getToken and requestProperty?

Narretz avatar Sep 18 '20 21:09 Narretz

@Narretz so because the first jwt config would throw an error when the first config wasn't found, it skipped the second and went to my error handler. I fixed by doing:

maybe there's another way? but this works just annoying having separate error handlers but oh well

   this.app
      .use(expressJwt(JWT_USER_AUTH))
      .use((err: any, _: any, __: any, next: any) => {
        if (err.name === "UnauthorizedError") next()
      })
      .use(expressJwt(JWT_STATION_AUTH))
      .use((err: any, _: any, __: any, next: any) => {
        if (err.name === "UnauthorizedError") next()
      })

JClackett avatar Sep 22 '20 11:09 JClackett

@JClackett but now everything passes through, even when you don't have any tokens. What you want is to combine your two middlewares into one that requires that at least one of the given middlewares (expressJwt(JWT_USER_AUTH) or expressJwt(JWT_STATION_AUTH)) succeeded.

vidstige avatar Dec 15 '20 17:12 vidstige

@vidstige I don't need it to throw an error though, just assign the appropriate property on the req object. this seems to be working as I expect? not sure what the best way of combining them would be

JClackett avatar Dec 17 '20 13:12 JClackett

Yeah, I ran into this exact same thing, and it's not clear how to combine them in a good way. The thing is if you only have one jwt-express middleware, then it will etiher populate req.user or throw an error. This ensures you do not serve sensitive data unless a valid token is provided. So after considering this, imho, the most sensible semantics would be if one first middlewares you're combining does not error, you bail out and are happy. If it errors, you go to the next one. Except when it's the last one, then you want it to error. So a bit messy there. I looked into the connect api and so on, and it's not clear to me how to do it in a neat way, but I'm sure it can be done.

One workaround I guess, is to do what you did and then have a fifth middleware after that checks that req.user was indeed populated, but feels brittle and furthermore you loose the exact error message (token expired or whatever). :thinking:

I made a custom secret provider instead as a workaround for the time being, but that as well comes with drawbacks.

vidstige avatar Dec 17 '20 13:12 vidstige