New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@iamjs/koa

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@iamjs/koa - npm Package Compare versions

Comparing version
2.0.14
to
2.0.16
+3
-6
dist/index.mjs
const n = {
merge: (s, t, r) => {
if (!s && !t)
return {};
if (!s)
return t;
if (!t)
return s;
if (!s && !t) return {};
if (!s) return t;
if (!t) return s;
if (r != null && r.preserve) {

@@ -10,0 +7,0 @@ const e = n.overlaps(s, t), i = n.omit(t, e);

import { AuthError, AuthManager, Roles, Schema, TAutorizeOptions } from '@iamjs/core';
import { Context, Next } from 'koa';
import { ActivityCallbackOptions, IKoaRoleManager, IKoaRoleManagerOptions, TKoaCheckOptions } from '../types';
declare class KoaRoleManager<T extends Roles<T>> extends AuthManager<T> implements IKoaRoleManager<T> {

@@ -5,0 +6,0 @@ schema: Schema<T>;

import { AuthError, IAuthManager, Roles, Schema, TAutorizeOptions } from '@iamjs/core';
import { Context, Next } from 'koa';
/**

@@ -4,0 +5,0 @@ * The options for the `onActivity` method

import { Role } from '@iamjs/core';
import { KoaRoleManager } from '@iamjs/koa';
import request from 'supertest';
import { default as request } from 'supertest';
declare const roleManager: KoaRoleManager<{

@@ -5,0 +6,0 @@ role: Role<{

{
"name": "@iamjs/koa",
"version": "2.0.14",
"version": "2.0.16",
"description": "This package contains middleware for integrating the authorization library into a Koa application. ",

@@ -61,6 +61,6 @@ "repository": "https://github.com/triyanox/iamjs",

},
"gitHead": "b83105dd9180ae853e68d16f95f64515e8cc3f34",
"gitHead": "0f41b633cbd0755524d6ed99252922ee3c2efac0",
"dependencies": {
"@iamjs/core": "^2.0.13"
"@iamjs/core": "^2.0.15"
}
}
+198
-203

@@ -6,6 +6,26 @@ # `@iamjs/koa`

This package contains the koa middleware for iamjs a library for easy role and permissions management for your koa application.
## Overview
The @iamjs/koa package provides Koa middleware for the iamjs library, enabling seamless integration of role-based access control (RBAC) into your Koa applications. This middleware simplifies the process of managing permissions and authorizing requests based on user roles in a Koa environment.
## Table of Contents
- [Installation](#installation)
- [Key Features](#key-features)
- [Usage](#usage)
- [Basic Authorization](#basic-authorization)
- [Advanced Usage with Dynamic Role Construction](#advanced-usage-with-dynamic-role-construction)
- [Custom Success and Error Handling](#custom-success-and-error-handling)
- [TypeScript Support](#typescript-support)
- [Logging User Activity](#logging-user-activity)
- [API Reference](#api-reference)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
## Installation
To use @iamjs/koa, you need to install both the core library and the Koa middleware:
```bash

@@ -21,24 +41,37 @@ npm install @iamjs/core @iamjs/koa

## Key Features
- Seamless integration with Koa applications
- Flexible role-based access control
- Support for custom success and error handling
- TypeScript support for improved type safety
- Activity logging for auditing and monitoring
## Usage
### Authorization
### Basic Authorization
You can use the `KoaRoleManager` to authorize a request in your koa application by creating a new instance and using the `check` method.
Here's a basic example of how to use the @iamjs/koa middleware for authorization:
Example:
```ts
import { Role, Schema } from '@iamjs/core';
import { ExpressRoleManager } from '@iamjs/koa';
```typescript
import Koa from 'koa';
import Router from 'koa-router';
import { Role, Schema } from '@iamjs/core';
import { KoaRoleManager } from '@iamjs/koa';
const role = new Role({
name: 'role',
const app = new Koa();
const router = new Router();
// Define a role
const userRole = new Role({
name: 'user',
config: {
resource1: {
base: 'crudl'
posts: {
base: 'crudl',
custom: {
publish: true
}
},
resource2: {
base: 'cr-dl'
comments: {
base: 'crud-'
}

@@ -48,6 +81,8 @@ }

// Create a schema with roles
const schema = new Schema({
roles : { role }
roles: { user: userRole }
});
// Initialize the KoaRoleManager
const roleManager = new KoaRoleManager({

@@ -57,8 +92,6 @@ schema,

ctx.status = 403;
ctx.body = 'Forbidden';
ctx.body = { error: 'Access denied' };
await next();
},
async onSuccess(ctx, next) {
ctx.status = 200;
ctx.body = 'Hello World from the success handler!';
await next();

@@ -68,43 +101,46 @@ }

router.get(
'/resource1',
// Use the middleware to protect a route
router.get('/posts',
roleManager.check({
resources: 'resource1',
actions: ['create', 'update'],
role: 'role',
strict: true
resources: 'posts',
actions: ['read', 'list'],
role: 'user'
}),
(_req, res) => {
res.send('Hello World!');
async (ctx) => {
ctx.body = { message: 'Posts retrieved successfully' };
}
);
app.use(router.routes());
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
```
### Advanced Usage
By using the `construct` option you can use the data from the request to build the role from its own permissions.
In this example, we define a `user` role with specific permissions for `posts` and `comments` resources. The `KoaRoleManager` is then used to check if the user has the required permissions to access the `/posts` route.
```ts
import { Role, Schema } from '@iamjs/core';
import { ExpressRoleManager } from '@iamjs/koa';
### Advanced Usage with Dynamic Role Construction
For more complex scenarios, you can dynamically construct roles based on request data:
```typescript
import Koa from 'koa';
import Router from 'koa-router';
import { Role, Schema } from '@iamjs/core';
import { KoaRoleManager } from '@iamjs/koa';
const role = new Role({
name: 'role',
config: {
resource1: {
base: 'crudl'
},
resource2: {
base: 'cr-dl'
}
}
});
// ... (previous role and schema setup)
const schema = new Schema({
roles : { role }
const app = new Koa();
const router = new Router();
// Middleware to attach user permissions to the context
app.use(async (ctx, next) => {
// In a real app, you'd fetch this from a database or JWT
ctx.state.userPermissions = userRole.toObject();
await next();
});
// Initialize the KoaRoleManager
const roleManager = new KoaRoleManager({

@@ -114,118 +150,63 @@ schema,

ctx.status = 403;
ctx.body = 'Forbidden';
ctx.body = { error: 'Access denied' };
await next();
},
async onSuccess(ctx, next) {
ctx.status = 200;
ctx.body = 'Hello World from the success handler!';
await next();
}
});
router.get(
'/resource1',
router.get('/posts',
roleManager.check({
resources: 'resource1',
actions: ['create', 'update'],
resources: 'posts',
actions: ['read', 'list'],
strict: true,
// get the role json or object from the request
data: async (ctx) => {
return ctx.permissions
}
construct: true,
data: async (ctx) => ctx.state.userPermissions
}),
(_req, res) => {
res.send('Hello World!');
async (ctx) => {
ctx.body = { message: 'Posts retrieved successfully' };
}
);
app.use(router.routes());
app.use(router.routes()).use(router.allowedMethods());
```
### Success and Error Handling
You can pass `onSuccess` and `onError` handlers to the `KoaRoleManager` constructor to handle the success and error cases.
This approach allows you to construct the role dynamically based on the user's actual permissions, which could be stored in a database or included in a JWT.
Example:
### Custom Success and Error Handling
You can customize how the middleware handles successful and failed authorization attempts:
```typescript
import { Role, Schema } from '@iamjs/core';
import { ExpressRoleManager } from '@iamjs/koa';
import Koa from 'koa';
import Router from 'koa-router';
const role = new Role({
name: 'role',
config: {
resource1: {
base: 'crudl'
},
resource2: {
base: 'cr-dl'
}
}
});
const schema = new Schema({
roles : { role }
});
const roleManager = new KoaRoleManager({
schema,
async onError(_err, ctx, next) {
async onError(err, ctx, next) {
console.error('Authorization failed:', err);
ctx.status = 403;
ctx.body = 'Forbidden';
ctx.body = {
error: 'Access denied',
details: err.message
};
await next();
},
async onSuccess(ctx, next) {
ctx.status = 200;
ctx.body = 'Hello World from the success handler!';
console.log('Authorization successful for user:', ctx.state.userId);
await next();
}
});
router.get(
'/resource1',
roleManager.check({
resources: 'resource1',
actions: ['create', 'update'],
role: 'role',
strict: true
}),
(_req, res) => {
res.send('Hello World!');
}
);
app.use(router.routes());
```
### Typescript Support
These handlers give you fine-grained control over the response sent to the client and allow for custom logging or other actions.
This package is written in typescript and has type definitions for all the exported types also the `check` method accepts a generic type which can be used to define the type of the context object.
### TypeScript Support
Example:
The @iamjs/koa package provides strong TypeScript support. You can use generics to specify the types of your context object:
```ts
import { Role, Schema } from '@iamjs/core';
import { ExpressRoleManager } from '@iamjs/koa';
import Koa from 'koa';
```typescript
import Koa, { Context } from 'koa';
import Router from 'koa-router';
const role = new Role({
name: 'role',
config: {
resource1: {
base: 'crudl'
},
resource2: {
base: 'cr-dl'
}
}
});
const schema = new Schema({
roles : { role }
});
interface CustomContext extends Context {
somekey: any
state: {
userId: string;
userPermissions: object;
};
}

@@ -235,10 +216,10 @@

schema,
async onError<CustomContext>(_err, ctx, next) {
ctx.status = 403;
ctx.body = 'Forbidden';
async onSuccess<CustomContext>(ctx, next) {
console.log('Authorized user:', ctx.state.userId);
await next();
},
async onSuccess<CustomContext>(ctx, next) {
ctx.status = 200;
ctx.body = 'Hello World from the success handler!';
async onError<CustomContext>(err, ctx, next) {
console.error(`User ${ctx.state.userId} unauthorized:`, err);
ctx.status = 403;
ctx.body = { error: 'Access denied' };
await next();

@@ -248,90 +229,104 @@ }

router.get(
'/resource1',
router.get('/posts',
roleManager.check<CustomContext>({
resources: 'resource1',
actions: ['create', 'update'],
role: 'role',
strict: true
resources: 'posts',
actions: ['read'],
role: 'user'
}),
(_req, res) => {
res.send('Hello World!');
async (ctx: CustomContext) => {
ctx.body = { message: `Posts retrieved for user ${ctx.state.userId}` };
}
);
app.use(router.routes());
```
### Save users activity
This ensures type safety throughout your application, reducing the likelihood of runtime errors.
You can save user activity using the `onActivity` method on the **KoaRoleManager**
### Logging User Activity
The `KoaRoleManager` allows you to log user activity, which can be useful for auditing and monitoring:
```typescript
import { Role, Schema } from "@iamjs/core";
import { ExpressRoleManager } from "@iamjs/koa";
import Koa from "koa";
import Router from "koa-router";
const role = new Role({
name: "role",
config: {
resource1: {
base: "crudl",
},
resource2: {
base: "cr-dl",
},
},
});
const schema = new Schema({
roles: { role },
});
interface CustomContext extends Context {
somekey: any;
}
const roleManager = new KoaRoleManager({
schema,
async onError<CustomContext>(_err, ctx, next) {
async onError(_err, ctx, next) {
ctx.status = 403;
ctx.body = "Forbidden";
ctx.body = { error: 'Access denied' };
await next();
},
async onSuccess<CustomContext>(ctx, next) {
ctx.status = 200;
ctx.body = "Hello World from the success handler!";
await next();
},
async onActivity(data) {
// save the activity object
},
console.log('User activity:', data);
// In a real application, you might want to save this to a database
await saveActivityLog(data);
}
});
```
router.get(
"/resource1",
roleManager.check<CustomContext>({
resources: "resource1",
actions: ["create", "update"],
role: "role",
strict: true,
}),
(_req, res) => {
res.send("Hello World!");
}
);
The `onActivity` handler receives an object with the following properties:
app.use(router.routes());
```
| Property | Description |
|------------|-----------------------------------------------------------|
| actions | The action(s) that were authorized |
| resources | The resource(s) that were accessed |
| role | The role used for authorization |
| success | Whether the authorization was successful |
| ctx | The Koa context object (for additional context) |
The data object contains:
## API Reference
| Name | Description |
| ---------- | ------------------------------------------------------------------------ |
| actions? | The action or actions that are authorized to be executed on the resource |
| resources? | The resource or resources that are authorized to be accessed |
| role? | The role that is used to authorize the request |
| success? | The status of the request |
| ctx? | The context object |
### KoaRoleManager
- `constructor(options: KoaRoleManagerOptions)`
- `check(options: CheckOptions): Koa.Middleware`
### KoaRoleManagerOptions
- `schema: Schema` - The iamjs Schema containing role definitions
- `onError?: (err: Error, ctx: Koa.Context, next: Koa.Next) => Promise<void>`
- `onSuccess?: (ctx: Koa.Context, next: Koa.Next) => Promise<void>`
- `onActivity?: (data: ActivityData) => Promise<void> | void`
### CheckOptions
- `resources: string | string[]` - The resource(s) being accessed
- `actions: string[]` - The action(s) being performed
- `role?: string` - The role to check against (if not using `construct`)
- `strict?: boolean` - Whether to require all specified permissions
- `construct?: boolean` - Whether to construct the role dynamically
- `data?: (ctx: Koa.Context) => Promise<object> | object` - Function to retrieve role data (if `construct` is true)
## Best Practices
1. **Use Environment-Specific Schemas**: Create different schemas for different environments (development, staging, production) to manage permissions effectively across your deployment pipeline.
2. **Implement Role Hierarchies**: Utilize role inheritance to create a hierarchy, reducing duplication and simplifying management.
3. **Granular Permissions**: Define permissions at a granular level for fine-tuned access control.
4. **Cache Role Data**: For improved performance, consider caching role data, especially if you're constructing roles dynamically.
5. **Audit Logs**: Implement comprehensive logging using the `onActivity` handler to maintain an audit trail of all authorization decisions.
6. **Error Handling**: Provide clear, informative error messages in your `onError` handler to aid in debugging and improve user experience.
7. **Regular Reviews**: Periodically review and update your role definitions and permissions to ensure they align with your application's evolving security requirements.
## Troubleshooting
- **Authorization Always Fails**: Ensure that the role name in `check()` matches the role defined in your schema.
- **TypeScript Errors**: Make sure you're using the correct types for your context object.
- **Performance Issues**: If you're seeing slow response times, consider caching role data or optimizing your `data` function in dynamic role construction.
## Contributing
We welcome contributions to @iamjs/koa! If you'd like to contribute, please:
1. Fork the repository
2. Create a new branch for your feature or bug fix
3. Make your changes and write tests if applicable
4. Submit a pull request with a clear description of your changes
Please see our [Contributing Guide](CONTRIBUTING.md) for more detailed information.
## License
@iamjs/koa is released under the [MIT License](LICENSE). See the LICENSE file for more details.