opa-express-middleware
Abstract
build.security provides simple development and management for your organization's authorization policy. opa-express-middleware is a Node.js Express middleware intended for performing authorization requests against build.security PDP(Policy Decision Point)/OPA.
Data Flow
Usage
Before you start we recommend completing the onboarding tutorial.
Important note
To simplify the setup process, the following example uses a local build.security PDP instance. If you are already familiar with how to run your PDP, You can also run a pdp on you environment (Dev/Prod, etc).
In that case, don't forget to change the hostname and the port in your code.
Simple usage
const express = require('express');
const bodyParser = require('body-parser');
const extAuthz = require('@build-security/opa-express-middleware');
const port = 3000;
const app = express();
const extAuthzMiddleware = extAuthz.authorize((req) => ({
port: 8181,
hostname: 'http://localhost',
policyPath: '/authz/allow',
}));
app.use(bodyParser.json(), extAuthzMiddleware);
app.listen(port, () => {
console.log(`Now listening on http://localhost:${port}`)
});
Mandatory configuration
-
hostname
: The hostname of the Policy Decision Point (PDP) -
port
: The port at which the OPA service is running -
policyPath
: Full path to the policy (including the rule) that decides whether requests should be authorized
Optional configuration
-
allowOnFailure
: Boolean. "Fail open" mechanism to allow access to the API in case the policy engine is not reachable. Default is false. -
includeBody
: Boolean. Whether or not to pass the request body to the policy engine. Default is true. -
includeHeaders
: Boolean. Whether or not to pass the request headers to the policy engine. Default is true -
timeout
: Integer. Amount of time to wait before request is abandoned and request is declared as failed. Default is 1000ms. -
enable
: Boolean. Whether or not to consult with the policy engine for the specific request. Default is true -
enrich
: Object. An object to attach to the request that is being sent to the policy engine. Default is an empty object {}
Advanced example
The following example will:
- consult with the policy engine only for GET requests
- add a field named "serviceId" with the value 1 to the request
- provide route parameters to the PDP as input. (For this to work, the middleware can't be applied globally using
app.use
) - an endpoint can declare the required permission the client needs in order to access it
const express = require('express');
const bodyParser = require('body-parser');
const extAuthz = require('@build-security/opa-express-middleware');
const app = express();
const extAuthzMiddleware = extAuthz.authorize((req) => ({
port: 8181,
hostname: 'http://localhost',
policyPath: '/authz/allow',
enable: req.method === "GET",
enrich: { serviceId: 1 }
}));
app.use(bodyParser.json());
app.get('/region/:region/users/:userId', extAuthz.permissions('user.read'), extAuthzMiddleware, (req, res) => {
res.send('allowed');
});
PDP Request example
This is what the input received by the PDP would look like.
{
"input":{
"request":{
"method":"GET",
"query":{
},
"path":"/region/israel/users/buildsec",
"scheme":"http",
"host":"localhost",
"body":{
},
"headers":{
"host":"localhost:3000",
"user-agent":"curl/7.64.1",
"accept":"*/*"
}
},
"source":{
"port":56038,
"ipAddress":"::1"
},
"destination":{
"port":3000,
"ipAddress":"::1"
},
"resources":{
"attributes":{
"region":"1",
"userId":"2"
},
"permissions":[
"user.read"
]
},
"serviceId":1
}
}
If everything works well you should receive the following response:
{
"decision_id":"ef414180-05bd-4817-9634-7d1537d5a657",
"result":true
}