Coder Social home page Coder Social logo

express-jwt-authz's Introduction

express-jwt-authz

Validate a JWTs scope to authorize access to an endpoint.

Install

$ npm install express-jwt-authz

express@^4.0.0 is a peer dependency. Make sure it is installed in your project.

Usage

Use together with express-jwt to both validate a JWT and make sure it has the correct permissions to call an endpoint.

:note: express-jwt sets the decoded JWT payload on req.auth since version 6.0.0, so make sure to set customUserKey: 'auth' in the options provided to express-jwt-authz if you are using that version or newer.

var jwt = require('express-jwt');
var jwtAuthz = require('express-jwt-authz');

var options = { customUserKey: 'auth' };
app.get('/users',
  jwt({ secret: 'shared_secret' }),
  jwtAuthz([ 'read:users' ], options),
  function(req, res) { ... });

If multiple scopes are provided, the user must have at least one of the specified scopes.

var options = { customUserKey: 'auth' };
app.post('/users',
  jwt({ secret: 'shared_secret' }),
  jwtAuthz([ 'read:users', 'write:users' ], options),
  function(req, res) { ... });

// This user will be granted access
var authorizedUser = {
  scope: 'read:users'
};

To check that the user has all the scopes provided, use the checkAllScopes: true option:

app.post('/users',
  jwt({ secret: 'shared_secret' }),
  jwtAuthz([ 'read:users', 'write:users' ], { checkAllScopes: true, customUserKey: 'auth' }),
  function(req, res) { ... });

// This user will have access
var authorizedUser = {
  scope: 'read:users write:users'
};

// This user will NOT have access
var unauthorizedUser = {
  scope: 'read:users'
};

The JWT must have a scope claim and it must either be a string of space-separated permissions or an array of strings. For example:

// String:
"write:users read:users"

// Array:
["write:users", "read:users"]

Options

  • failWithError: When set to true, will forward errors to next instead of ending the response directly. Defaults to false.
  • checkAllScopes: When set to true, all the expected scopes will be checked against the user's scopes. Defaults to false.
  • customUserKey: The property name to check for the scope key. By default, permissions are checked against req.user, but you can change it to be req.myCustomUserKey with this option. Defaults to user.
  • customScopeKey: The property name to check for the actual scope. By default, permissions are checked against user.scope, but you can change it to be user.myCustomScopeKey with this option. Defaults to scope.

Issue Reporting

If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

Author

Auth0

License

This project is licensed under the MIT license. See the LICENSE file for more info.

express-jwt-authz's People

Contributors

adamjmcgrath avatar adrianroworth avatar akehir avatar anishkny avatar crew-security avatar dschenkelman avatar eugeniop avatar evansims avatar ewanharris avatar frederikprijck avatar iomatrix avatar jake-wickstrom avatar luisrudge avatar magmastonealex avatar michael-lowe-nz avatar widcket avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-jwt-authz's Issues

Inquiry: Using `jwtAuthz` in a Route Handler function

Hi! Want to first thank the developers for making express-jwt-authz and express-jwt ๐Ÿ™Œ

Describe the problem you'd like to have solved

I am trying to use jwtAuthz within a Route Handler function, like such:

var jwt = require('express-jwt');
var jwtAuthz = require('express-jwt-authz');

var options = {};
app.get('/users',
  jwt({ secret: 'shared_secret' }),
  // jwtAuthz([ 'read:users' ], options),
  function(req, res) {
    jwtAuthz([ 'read:users' ], options) // not sure how to make this work here
  }
);

Additional context

I have the following routes:

app.get('/a',
   jwtAuthz(['read:a']),
   ...
);

app.get('/b',
   jwtAuthz(['read:b']),
   ...
);

app.get('/c',
   jwtAuthz(['read:c']),
   ...
);

I want to try the following:

app.get('/:letter',
   function(req, res) {
     jwtAuthz([ `read:${req.params.letter}` ])
   }
);

Hope this makes sense (I am also not sure if this is considered bad practice or not, as I am fairly new to Auth0)

Make Typescript Play Nicely with JWT-Authz

Describe the problem you'd like to have solved

Does anyone know a clean way to handle typescript with this library. Not super versed in typescript and its nuances. Was wondering how I could cleanly implement a route with this library that I don't have to give my own custom type to the req param.

Describe the ideal solution

If I have:

router.get("/", checkJWT, jwtAuthz(...), (req, res) => {
    console.log(req.user) //<--- here is where I normally get an issue because user doesn't exist on the req object.
})

I wouldn't need to clarify that the req object has a type. Again, not sure if this is possible for the library or if it NEEDS to be on my end

Alternatives and current work-arounds

The current workaround I have is to just extend the express.request interface like so:

export interface AuthenticatedRequest extends Request {
  user?: string;
}

Then in my endpoint I would :

router.get(
  "/",
  checkJWT,
  jwtAuthz(...),
  async (req: AuthenticatedRequest, res) => {
})

Additional context

Again, if there is a way to implement this through the jwt library, that would be great.

Thanks

Version on NPM doesn't match Github repo contents

Description

Package on NPM is v2.3.1 and doesn't include the types

Package in this repo master is v2.3.0 but does include the types

Rolling back to v2.3.0 from npm doesn't contain types but is different package contents

๐Ÿค” what the heck is going on here?

Reproduction

Compare the published npm package with the code here on Github

Environment

n/a

Add Typescript Support

Describe the problem you'd like to have solved

Currently, there is no .d.ts file for this module, meaning it does not play well with typescript projects.

Describe the ideal solution

Add a .d.ts file to this module or create a @types/express-jwt-authz module to allow typescript projects to intelligently use this module

Alternatives and current work-arounds

Currently, I am requiring the library as a plain JS module

Misleading/incorrect documentation

The documentation contains the following:


If multiple scopes are provided, the user must have any the required scopes.

app.post('/users',
  jwt({ secret: 'shared_secret' }),
  jwtAuthz([ 'read:users', 'write:users' ], {}),
  function(req, res) { ... });

// This user will be denied access
var authorizedUser = {
  scope: 'read:users'
};

I believe the inline comment is incorrect and should be changed to:

// This user will be granted access

Am I understanding how this module is intended to behave? Is this indeed an error in the documentation?

res.send args are deprecated

If the user scopes are not sufficient to access the resource, the error function uses

return res.send(401, 'Insufficient scope'); to complete the Express response.

However, this style is now deprecated; Express reports the following on the console:

express deprecated res.send(status, body): Use res.status(status).send(body) instead at node_modules\express-jwt-authz\lib\index.js:2:14

Suggest replacing the on-error function with:

return res.status(401).send('Insufficient scope');

before this breaks.

the req.user key is hardcoded

express-jwt allows us to customize the key for requestProperty. It would be nice to have the same functionality here

No types for express-jwt-authz

I couldn't find any types for this module, i.e., npm install @types/express-jtw-authz.

This declaration code (index.d.ts) works either side-by-side with lib/index.js in the node_modules/express-jwt-authz folder (v2.3.1), or manually placed in node_modules/@types/express-jwt-authz.

index.d.ts:

import { Request, Response, NextFunction } from 'express';

declare global {
    namespace Express {
        interface Request {
            user: any;
        }
    }
}

export interface IAuthzOptions {
    failWithError: boolean;
    checkAllScopes: boolean;
    customScopeKey: string;
}

export default function(expectedScopes: string[], options?: IAuthzOptions): (req: Request, res: Response, next: NextFunction) => void;

Possible security vulnerability when multiple values passed in expectedScopes

Description

If an endpoint requires multiple scopes (expectedScopes.length > 1), then it is possible to gain access if the user has only one of the required scopes.
This is because this piece of code only checks if some of the expected scopes match:
var allowed = expectedScopes.some(function(scope){ return scopes.indexOf(scope) !== -1; });

Example

If a user has scopes ['read:something'] and expected scopes are ['read:something', 'write:something'], user will be able to access the endpoint.

403 or 401?

The documentation on the website reads:

The checkJwt middleware shown above checks if the user's Access Token included in the request is valid. If the token is not valid, the user gets a 401 Authorization error when they try to access the endpoints.

But the code is sending a 403.

Edit 403 is correct. The docs are wrong.
Which one is the correct thing to send? I would think 401 with a WWW-Authenticate header.

Need to push to NPMJS

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Please read through the template below and answer all relevant questions. Your additional work here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Description

Provide a clear and concise description of the issue, including what you expected to happen.

The documentation on NPMJS still shows the old wrong doc for behavior when multiple scopes are provided.

Reproduction

Detail the steps taken to reproduce this error, what was expected, and whether this issue can be reproduced consistently or if it is intermittent.

Where applicable, please include:

  • Code sample to reproduce the issue
  • Log files (redact/remove sensitive information)
  • Application settings (redact/remove sensitive information)
  • Screenshots

https://www.npmjs.com/package/express-jwt-authz

This was fixed in 39d1c1e it just needs to be pushed to NPMJS.

Environment

Please provide the following:

  • Version of this library used:
  • Version of the platform or framework used, if applicable:
  • Other relevant versions (language, server software, OS, browser):
  • Other modules/plugins/libraries that might be involved:

Error handling in express routes

I am using 'express-jwt-authz' to validate the scope of a jwt token, I implemented the flow like below. Here when I am calling 'checkScopes' function from my routes but it will never return the result, the callback of 'jwtAuthz' is not throwing any success or error condition. How to check error handling in 'express-jwt-authz' auth npm.

Middleware 

    validation.js 

    const jwt = require('express-jwt');
    const jwtAuthz = require('express-jwt-authz');
    const jwksRsa = require('jwks-rsa');
    const config = require('../config/config');
    module.exports.checkScopes = function(options) {
      return function(req, res, next) {
        jwtAuthz(options, {customScopeKey: 'http://user.com/scopes'}, function(error) {
          if (error) {
            console.log('error', error)
          } else {
            console.log('result never called')
            next();
          }
        })
      }
    }

Routes 
    invitation.js 

    const express = require('express');
    const router = express.Router();
    const jwtValidation = require('../middleware/jwtValidation');
    router.get('/', jwtValidation.checkScopes([ 'create:users' ]), invitation.getAllInvitation);

added typescript support added into repo but not published on npm

Description

added typescript support added into repo but not published

Reproduction

add authz as a middleware
it throws error

node_modules/path-to-regexp/index.js:63 path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?')) ^ TypeError: Cannot read property 'length' of undefined

Environment

Please provide the following:

Acceptance Criteria

release new version that supports typescript

Customizable error messages

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

Currently there is only one Error Message 'Insufficient scope' There should be an option for more.

Describe the ideal solution

Include an additional AuthzOptionslike customErrorMessage and use that if option is set.

Alternatives and current work-arounds

No work-around right now.

Additional context

This could be useful for external APIs to provide a meaningful error message.

Insufficient scope error caused by undefined field in jwtAuthz

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Please read through the template below and answer all relevant questions. Your additional work here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Description

The field selection from jwtAuthz function appear to be incorrect. I was running into the exact same issue as reported here. Except specifying a customScopeKey did not solve the problem. Looking at the output of the request and the function itself, there is no field on the JWT token called user but that is what the function is requesting. Revising the userKey field to auth corrects the behaviour.

Reproduction

The middleware I was using:
app.get('/userbased', checkJwt, jwtAuthz(['read:ssim']), (req, res) => { console.log('Request', req['auth']); res.send('Role based user authentication is working'); });

The edit I made to the jwtAuthz function
let userKey = 'auth';

Environment

Please provide the following:

  • Version of this library used: [email protected]
  • Version of the platform or framework used, if applicable: NodeJS & React
  • Other modules/plugins/libraries that might be involved: jwks-rsa & express-jwt for JWT authentication

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.