Daniel Wondyifraw
Daniel Wondyifraw

Reputation: 7723

user and role authorization in swagger api express

guys

on my exisiting api i already have user authhication using Bearer security. Using http header api_key and later tokens.

My problem seems to be i have diffefrent end point that are only need to be consumed based on roles.

For example to post a new user :

POST user should only be authenticated to user with admin role.

I have looked at the swagger spec here but nothing i could find on thier docuemation and google as well.

Please could give me some brain stroming idea ? below is my access verifaction code in nodejs and express.

swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
  // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
  app.use(middleware.swaggerMetadata());

  app.use(middleware.swaggerSecurity({
    Bearer: function(req,def,apiKey,next){
        apiKey= apiKey.slice(7)
        debug("token check",def,apiKey)
        var ok=checkToken(apiKey)
        if(ok) {
          req.user=ok
          debug('Token is ok')
          return next()
        }
        debug("Invalid token",apiKey)
        var err=Error("Invalid token")
        err.statusCode=403
        next(err)
    }
  }));

Upvotes: 2

Views: 3674

Answers (1)

Porlune
Porlune

Reputation: 749

As of this writing, the solution is still homebrewing. Swagger does not, save through oAuth scopes or using a "hacky" api-key security definition (https://stackoverflow.com/a/40222161/3736937), have a built in RBAC mechanism.

Fortunately, we can create some pretty basic middleware to handle the problem because swagger does allow us to add x-swagger-* members to the swagger definition.

So here's what I did:

  1. Add x-swagger-roles to each endpoint that requires RBAC (Role-based Access Control)

    paths:
      "/":
        x-swagger-router-controller: getStatus
        get:
          operationId: getStatus
          x-swagger-roles:
            - admin
          tags:
            - "users"
          summary: "Returns message: 'working'"
          description: "default endpoint for testing"
          responses:
            $ref: "#/definitions/AnyResponse"
    
  2. Place middleware before swagger-node-runner is registered with the application. In our case we're using expressjs, so the connect middleware is used.

    var findOne = function (haystack, arr) {
        return arr.some(function (v) {
            return haystack.indexOf(v) >= 0;
        });
    };
    
    app.use(function(req, res, next) {
      var operation = runner.getOperation(req);
      if(operation && operation.definition) {
        var definition = operation.definition;
        var requiredRoles = definition['x-swagger-roles'];
    
        // if the endpoint has no required roles then go to the next route
        if(!requiredRoles) return next();
    
        // get the users roles
        var userRoles = req.session.roles; // this may differ for you
    
        // if any roles match then go to the next route
        if(findOne(userRoles, requiredRoles)) return next();
    
        // if no roles match then assert that this endpoint is forbidden
        else return res.sendStatus(403);
      }
      next();
    })
    
    // it's important to register the middleware after the role check
    runner.expressMiddleware().register(app);
    

Notes:

  1. This code has not been tested in production, and should be reviewed by a security professional.

  2. x-swagger-roles will not appear in your swagger-ui without altering it, which is beyond the scope of this answer.

Upvotes: 2

Related Questions