Authorization
Novel uses the CASL library to provide authorization checks for all the routes and actions you need for your SaaS.
Configuration
In /config/auth.js
there is a roles object that you can modify to add role IDs and permission keys to.
/**
* These are roles within the app that can be assigned to users.
*
* They have permissions that can be applied per route. Additional permission checks can be added
* per transaction via casl/ability.
*
* Make sure you update app/(app)/organization/team/members.tsx if you modify this.
*/
roles: {
superuser: ['all', 'admin'],
admin: ['read', 'write', 'delete'],
user: ['read', 'write'],
},
You can add as many roles you need here, and as many permissions applied to the role here.
These are then auto-loaded during start up time and applied to a global authorizer and a session based authorizer.
Permission
The Permission
object is a class that you can use to organize permissions in your application.
const permit = new Permission(anyActorWithAnId);
permit.allow('read', Post);
permit.deny('delete', Post);
await permit.persist();
// or fetch a stored permission
const permit = await Permission.fetch(anActorWithAnId);
new Permission(ObjectWithId)
new Permission(ObjectWithId)
This creates a new Permission object that can be serialized later on. You can use this to temporarily create permissions in your feature code.
You can persist the permissions to database using .persist()
below.
permit.allow(action: String, subject: String | ObjectWithId)
permit.allow(action: String, subject: String | ObjectWithId)
This defines what you can use in the Permission object using the CASL Ability .can
or .cannot
. The signature for this is the same.
permit.deny(action: String, subject: String | ObjectWithId)
permit.deny(action: String, subject: String | ObjectWithId)
This is the opposite of allow you can use in the Permission object using the CASL Ability .can
or .cannot
. The signature for this is the same.
permit.build(): Ability
permit.build(): Ability
This is an internal abstraction to CASL's Ability.build function. This makes it so that you can perform CASL functions against the Permission Object
const permit = new Permission(anyActorWithAnId);
permit.allow('read', Post);
permit.deny('delete', Post);
const permissions = permit.build();
permission.can('read', Post); // returns true
await permit.persist()
await permit.persist()
This persists the permissions defined during the lifecycle of the Permission object. It generates a serialized permission records, one row per action/scope into the access_control
table.
await Permission.fetch(actor: String | ObjectWithId)
await Permission.fetch(actor: String | ObjectWithId)
This is similar to new Permission(ObjectWithId)
but for an actor that has been persisted.
const permissions = await Permission.fetch(anyActorWithAnId);
permission.can('read', Post); // returns true
Using with an API
It is important to be familiar with both authorization modes of Novel API. Discussed below:
Combine the above with the request helpers associated with permit.allow
and permit.deny
.
Changelog
2024-12-20 - Initial Documentation
Last updated
Was this helpful?