As web applications evolve and grow in complexity, the need for advanced security measures also increases. One particular area of focus is the authorization process, which controls who has access to what within an application. But how do you manage this efficiently?
Introducing iamjs, a robust, performance-driven authorization library engineered to streamline your authorization process through a schema-based approach. Composed of several modules such as @iamjs/core, @iamjs/express, @iamjs/koa, @iamjs/next and @iamjs/react, iamjs has something to accommodate a variety of programming environments.
Features:
iamjs is a feature-rich access control library that offers high performance and a wide range of capabilities. It revolutionizes the authorization process by empowering developers with efficient tools that simplify their workflow. Here are some key features that make iamjs stand out:
- Role-based Access Control: iamjs allows users to effortlessly assign roles with fine-grained permissions, enabling precise control over resource access and security.
- Versatile Programming Environment Support: With iamjs, you can seamlessly integrate access control into various programming environments, including Express.js, Koa.js, Next.js, and React. This flexibility ensures that you can use iamjs across your entire tech stack.
- Customizable Permissions: Tailoring access permissions to your specific requirements is a breeze with iamjs. You have the freedom to define and configure custom permissions for individual resources and actions, empowering you to establish a robust security model.
- Type safety: iamjs is built with TypeScript, ensuring type safety and reducing the likelihood of errors in your code.
- Effortless Testing: iamjs is equipped with comprehensive testing tools that simplify the process of validating your authorization logic. This feature ensures that your application remains secure throughout development, giving you peace of mind.
@iamjs/core:
The @iamjs/core
module provides the core logic for the library, empowering developers with a toolkit that makes building access control systems a simpler task.
For instance, let's begin by defining two roles, user
and admin
, both equipped with specific permissions for different actions and resources:
import { AuthManager, Role, Schema } from "@iamjs/core";
const roles = {
user: new Role({
name: "user",
config: {
user: {
base: "-r--l",
custom: {
ban: false,
},
},
post: {
base: "crudl",
custom: {
publish: true,
},
},
},
}),
admin: new Role({
name: "admin",
config: {
user: {
base: "crudl",
custom: {
ban: true,
},
},
post: {
base: "crudl",
custom: {
publish: true,
},
},
},
}),
};
const schema = new Schema({
roles,
});
const auth = new AuthManager(schema);
With the roles and authorization schema defined, you can now utilize the AuthManager class to perform authorization checks effortlessly:
const isAdminAuthorized = auth.authorize({
role: "admin",
actions: ["ban", "create"],
resources: "user",
}); // true
const isUserAuthorized = auth.authorize({
role: "user",
actions: ["read", "create"],
resources: ["post", "user"],
strict: true,
}); // false
@iamjs/express:
For Express.js enthusiasts, @iamjs/express
provides seamless integration with the Express.js framework. Leveraging this module, you can easily set up middleware for assigning roles and checking authorization, amplifying your application's security layer in just a few lines of code:
import { Role, Schema } from '@iamjs/core';
import { ExpressRoleManager } from '@iamjs/express';
import express from 'express';
const role = new Role({
name: 'role',
config: {
resource1: {
base: 'crudl'
},
resource2: {
base: 'cr-dl',
custom: {
'create a new user': false
}
}
}
});
const schema = new Schema({
role
});
const roleManager = new ExpressRoleManager({
schema: schema,
onError(_err, _req, res, _next) {
res.status(403).send('Forbidden');
},
onSucess(_req, res, _next) {
res.status(200).send('Hello World from the success handler!');
}
});
const app = express();
app.get(
'/resource1',
roleManager.check({
resources: 'resource1', // the resources to be accessed
actions: ['create', 'update'], // the actions to be performed
role: 'role',// the role to check
strict: true // make the checks run in strict mode
// additionnaly you can construct role from permissions by using the construct option
construct: true,
data: async(req){
return schema.get(req.role).toObject()
}
}),
(_req, res) => {
res.send('Hello World!');
}
);
@iamjs/react:
Finally, weaving this into a React setting, @iamjs/react
simplifies checking permissions within your components. It introduces a nifty hook - useAuthorize
, allowing you to control component rendering based on user roles:
Import useAuthorize
and createSchema
from the package
import { Role } from "@iamjs/core";
import { createSchema, useAuthorization } from "@iamjs/react";
import { useEffect, useState } from "react";
Create the initial schema with a default roles
const schema = createSchema({
user: new Role({
name: 'user',
description: 'User role',
meta: {
name: 'user'
},
config: {
books: {
base: 'crudl',
custom: {
upgrade: true,
downgrade: false,
sort: true
}
}
}
})
Create your own hook to fetch the user's permissions from your backend
const useUser = () => {
const { build } = useAuthorization(schema);
const [userRole, setUserRole] = useState(null);
useEffect(() => {
// Call the API endpoint to fetch user permissions
fetch("/permssions")
.then((response) => response.json())
.then((data) => {
// Build the role based on the received permissions
const builtRole = build(data);
setUserRole(builtRole);
})
.catch((error) => {
console.error("Error fetching user permissions:", error);
});
}, []);
return userRole;
};
Use your own hook to check the permissions or to check the user's permissions or render components conditionally
const Component = () => {
const userRole = useUser();
if (!userRole) {
return <div>Loading...</div>;
}
const { can, Show } = userRole;
return (
<div>
<div>{can("books", "create").toString()}</div>
<Show resources="books" actions="create">
<div>Rendered if user has 'create' permission for 'books'</div>
</Show>
</div>
);
};
Additionally your use the Show
and can
methods directly from useAuthorize
and use the roles you provided in the schema to render conditionally or check the users permissions
const { can, Show } = useAuthorization(schema);
const canDo = can("user", "books", "create").toString(); // 'true'
<Show role="user" resources="books" actions="create">
<div>can show</div>
</Show>;
Conclusion
iamjs is a powerful and versatile library for access control that simplifies the authorization process using a schema-based approach. With features such as role-based access control, customizable permissions, and support for a variety of programming environments, iamjs provides a comprehensive solution for building secure and robust web applications.
To learn more about iamjs, check out the official documentation here. And if you're interested in contributing to the project, head over to the repository on GitHub.