I’m interested in serving a subsection of the data in Bayanat on a public website. I’m wondering if there are good ways or established patterns for doing this. Ideally I would just built a frontend and have it consume data from the Bayanat APIs and configure Bayanat to only allow this website to consume data via CORS rules and rate limit API requests since it’s all public.
Here are some related questions I have:
Is there an API reference for Bayanat anywhere, e.g. something like swagger/redoc documentation for the API?
Is there a good way to label/annotate data as suitable for public consumption, e.g. with a public label or some other method?
If you remove it in theory anonymous users can access these endpoints, but then individual endpoints have checks for roles and access control, so you’ll need to remove all of that.
An easier solution would be to create a “public” account. You can also log in users automatically to this account. Bayanat has access control feature. However, this is again not how Bayanat is designed and intended to be used so we advise against it.
Are those API endpoints public? I generated the openapi spec there using npx redocly build-docs api.yaml - couldn’t see anywhere it’s served in the app. I then opened the html file, but can’t figure out how to hit those endpoints on my bayanat instance, i.e. if I make a request to https://<domain>.com/api/check-admin it gives me a 404. Trying to login via a HTTP request to the login endpoint also says I need a CSRF token, so wondering if there is even a login flow for a HTTP client versus a user filling in the form.
Architecturally, it sounds like it might make more sense to periodically export public data from Bayanat into another system designed specifically for public consumption, e.g. some new postgres table for public data + a new s3 bucket for public media + a new API designed for public consumption, i.e. with heavy rate limiting etc.
Do you have any support for the stuff mentioned in 2 or would that all require custom builds?
Only a handful of endpoints are public (login, wizard setup,etc…). Everything else is protected by session, roles and permissions. /api/check-admin is public but only on during initial setup, after that it’s disabled (for obvious security purposes). The api docs are not served in the app but they are written using openapi3 so they are easy to render, try to paste the file into: https://editor.swagger.io/
Regarding the second question, the short answer is Bayanat doesn’t really support this at the moment. There’s an export tool that can help you export data in bulk in json format which you can theoretically import into another system. Lastly you can consider creating a public user. This is only thinkable if all the data in the system is public. Even though bayanat technically have a access control feature, we still strongly advise against doing this with a database that has public and sensitive data that you want to keep from public.
We have an internal sync tool which can sync data between two bayanat servers, but it might require some tinkering for you to achieve the results you want. This feature makes all core components accessible using api key. I’m happy to share this code with you so you can at least have an idea on how to build something that would work with another system.
Hi, as additional info, here is an example of how you can set up login via Postman using a script:
Create a new environment, add username, password and baseUrl variables and fill them in.
In your POST /login request, go to Scripts tab, and add the following script as a Pre-request script. This script sends a GET request to baseUrl, which should render the login page, then uses regex to capture the hidden csrf value from the rendered page and set it both in current request’s body, and in your Postman environment.
// Send a GET request to fetch the initial page and extract the CSRF token
pm.sendRequest(`${pm.variables.get("baseUrl")}`, function (err, response) {
// Check if there was an error
if (err) {
console.log("Error fetching CSRF token:", err);
} else {
// Extract CSRF token from the response
const responseBody = response.text();
const regexPattern = /<input id="csrf_token" name="csrf_token" type="hidden" value="([^"]+)"/;
const matches = responseBody.match(regexPattern);
if (matches && matches.length > 1) {
// Found the CSRF token, save it in a variable
const csrfToken = matches[1];
console.log("CSRF Token:", csrfToken);
// Now, you can use this CSRF token in your login request.
// If you're sending the login request with form data:
pm.request.body.update({
mode: 'urlencoded',
urlencoded: [
{ key: 'csrf_token', value: csrfToken },
{key: 'username', value: pm.environment.get("username")},
{key: 'password', value: pm.environment.get("password")}
]
});
// Or set it as an environment variable if it's used in multiple requests or in the URL/body as a variable
pm.environment.set("csrf_token", csrfToken);
} else {
console.log("CSRF token not found in the response.");
}
}
});
You can then send your POST /login request, which should successfully authenticate and get a valid session cookie.