1.1.0 • Published 1 year ago

@oas-tools/auth v1.1.0

Weekly downloads
-
License
Apache-2.0
Repository
-
Last release
1 year ago

OAS Auth

NPM

npm node-current npm Node.js CI Conventional Commits

Known Vulnerabilities Coverage Status

Contents

OAS Auth

OAS Auth is an npm package that groups a series of handlers and middleware functions that can be integrated inside OAS Tools Core Library in order to perform different kinds of validation towards security and authentication. Some of the contents in this package may not be compatible with older versions of NodeJS, please check the compatibility chart at the end of this document.

JWT Bearer Token

Security Handler

The security handler function extends OAS-Security native middleware in order to verify the token provided through the Authorization header in request. This function must be included in OAS-Tools options object for OAS-Security to be able to use it.

usage

Take into account that security middleware must be enabled through config cfg.middleware.security.disable = false and secSchemeName must match the name specified for that security scheme in the OpenAPI document.

import { bearerJwt } from 'oas-auth/handlers';

var options_object = {
    middleware: {
      security: {
        auth: {
          secSchemeName: bearerJwt({issuer: 'issuerName', secret: 'secretKey'})
        }
      }
    }
  };

oasTools.initialize(app, options_object).then(() => ...)

config

The handler function takes three possible arguments:

TypeRequiredDescription
issuerString or ArrayValid values for the iss field
secretString or BufferSecret used to sign the token
algoritmsArrayAllowed algorithms, default ["HS256"]

errors

Upon JWT token verification, the following errors may be throwed and could be handled through a custom handling function specified in the OAS-Tools configuration under middleware.error.customHandler.

  • JsonWebTokenError: Verification failed due to some error concerning JWT. Check the possible messages.
  • SecurityError: The token provided does not match Bearer <token> structure. Handled automatically by the native error handler to respond 401 Unauthorized.

Authentication Middleware

The OASBearerJWT authentication middleware is an external resource that can be included inside the OAS-Tools Core Library through the use function. This middleware will be registered inside the express chain in order to check access permissions for the API operations.

For this middleware to work, you first need to declare a security scheme in the OpenAPI document with type http, scheme bearer and bearer format JWT. See OpenAPI docs on how to use Bearer Authentication.

import { OASBearerJWT } from 'oas-auth/middleware';

const authCfg= {acl: { secSchemeName:'route/to/permissions.json' }}

oasTools.use(OASBearerJWT, authCfg, 2);
oasTools.initialize(app, options_object).then(() => ...)

config

The configuration object can be provided through the use function like shown in the example above, or through the OpenAPI document, under components.securitySchemes.[schemeName].x-acl-config. See setting permission section below. Available configuration options are listed in the following table.

TypeDescription
roleBindingStringBinds role to another attribute of the JWT
aclObjectAccess control configuration
acl.[schemeName]Object or StringPermission declaration. Can be object or a file path
checkOwnershipFunctionFunction that checks wether some resource is owned or not by the client

setting permission

Permissions are declared upon middleware initialization, they can be set through config.acl or through x-acl-config field inside security schemes in the OpenAPI document. The structure of the JSON object used by the middleware to declare those authentication rules is the one used by Access Control since OASBearerJWT relies in that library under the hood.

The following snippet shows how permissions are declared inside the OpenAPI Document.

...
securitySchemes:
    bearerjwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      x-acl-config:
        user:
          example/endpoint/{parameter}:
            "read:own":
              - "*"

Similarly, the declaration above can be translated into a JS object or written to a JSON file and then included inside the ACL configuration for the middleware.

//JS object
const authCfg = {
  acl: {
    bearerjwt: {
      user: {
        example/endpoint/{parameter}: { "read:own" : ["*"] }
      }
    }
  } 
}

In both cases we are defining a role user that have access to example/endpoint/{parameter}when that resource is owned by him. That means the JWT payload must contain an attribute role (or an attribute with the same name specified in config.roleBinding) and an attribute parameter so the middleware can validate if that user owns that resource.

The parameter attribute in the JWT payload can be a single value or a list of allowed values. This way, if the JWT payload contains {role: user, parameter: [1,3,5]} the following requests will be handled has follows:

  • GET /example/endpoint/1 returns 200 OK
  • GET /example/endpoint/3 returns 200 OK
  • GET /example/endpoint/4 returns 403 Forbidden
  • GET /example/endpoint/271 returns 403 Forbidden

Bear in mind that parameter is influenced by serialization rules and must be expressed according to that.

If the JWT payload contains a different attribute for parameter, you may bind parameterto that attribute, using x-acl-binding when declaring parameter in the OpenAPI document.

...
parameters:
  - name: parameter
    required: true
    in: path
    schema:
      type: integer
    x-acl-binding: JWTParamAttribute
...

Finally, in case no role is specified in the JWT payload, the middleware will assume an anonymous role that only has read access to those operations that doesn't include parameters of any type. This role can be overriden by configuration.

Checking ownership

The middleware can be configured to check wether a resource is owned by the client or not. This is done by providing a function that receives the JWT payload and the parameters name and value, to retur a boolean value. The function must be provided through config.checkOwnership

    authCfg.checkOwnership = async (decoded, paramName, paramValue) => {
      return await Actor.findOne({ [paramName]: paramValue }).then(actor => actor?.email === decoded?.email);
    }

NOTE: Bear in mind that the function MUST return a boolean value. Promises are suported, but you will need to wait for them to resolve by using await or .then(). If you don't return a boolean value, the middleware will assume that the resource is not owned by the client and will return 403 Forbidden.

Compatibility chart

The following chart shows which versions of NodeJS are compatible with each of the contents inside this package.