Installations
npm install @exobase/use-authorization
Developer Guide
Typescript
Yes
Module System
CommonJS, ESM
Node Version
18.10.0
NPM Version
lerna/4.0.0/node@v18.10.0+arm64 (darwin)
Score
74.2
Supply Chain
97.5
Quality
75.4
Maintenance
100
Vulnerability
99.3
License
Releases
Unable to fetch releases
Love this project? Help keep it running — sponsor us today! 🚀
Download Statistics
Total Downloads
779
Last Day
1
Last Week
2
Last Month
10
Last Year
95
Bundle Size
32.94 kB
Minified
8.20 kB
Minified + Gzipped
Package Meta Information
Latest Version
1.0.0-rc.5
Package Id
@exobase/use-authorization@1.0.0-rc.5
Unpacked Size
102.74 kB
Size
28.30 kB
File Count
51
NPM Version
lerna/4.0.0/node@v18.10.0+arm64 (darwin)
Node Version
18.10.0
Total Downloads
Cumulative downloads
Total Downloads
779
Last day
0%
1
Compared to previous day
Last week
0%
2
Compared to previous week
Last month
25%
10
Compared to previous month
Last year
-64.4%
95
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
2
title: 'useAuthorization' description: 'A role/permission authorization hook' group: 'Hooks' badge: 'Auth'
Exobase hook to check if a request is authorized for a given resource
Install
1yarn add @exobase/use-authorization 2# or 3yarn add @exobase/hooks
Import
1import { useAuthorization } from '@exobase/use-authorization' 2// or 3import { useAuthorization } from '@exobase/hooks'
Usage
1import { compose } from 'radash' 2import type { Props } from '@exobase/core' 3import { useNext } from '@exobase/use-next' 4import { useAuthorization, useTokenAuth } from '@exobase/hooks' 5import type { TokenAuth } from '@exobase/hooks' 6 7type Args = { 8 id: string 9 price: number 10} 11 12type Services = { 13 db: Database 14} 15 16export const updateListing = async ({ 17 args, 18 services 19}: Props<Args, Services, TokenAuth>) => { 20 const { id, price } = args 21 const { db } = services 22 await db.listings.update(id, { price }) 23} 24 25export default compose( 26 useNext(), 27 useJsonBody(z => ({ 28 id: z.string(), 29 price: z.number() 30 })), 31 useTokenAuth(config.auth.tokens.secret), 32 useAuthorization<Props<Args, {}, TokenAuth>>({ 33 permissions: ({ auth }) => auth.token.permissions, 34 require: ({ args }) => `allow::write::com.craigslist/listings/${args.id}` 35 }), 36 useServices<Services>({ 37 db: () => new Database() 38 }) 39 updateListing 40)
CANI
This hook includes it's own permission engine. It uses a URI prefix trie to check if a user has the required permissions. Every permission has 3 parts and an optional name (helpful to use on endpoints for better errors and DX).
1export type Permission = { 2 acl: 'allow' | 'deny' 3 scope: string 4 uri: string 5 name: string | null 6}
ACL
Most permissions will have an acl
of allow, if you want to give a user an anti-permisson (one that restricts their ability) give it an acl
of 'deny'
.
Scope
The scope is anything you like, we typically use values like read
, write
, or edit
. Use the *
value as a wildcard. If a user has the *
scope on the required resource it will pass verification, no matter the required scope.
Uri
A forward slash seperated string, or path, to the unique resource. Use the *
value as a wildcard. We like to start the path with the domain of the site were working on.
github/owner/rayepps/repo/exobase-js
github/owner/rayepps/repo/exobase-js/settings
github/owner/rayepps/repo/*/*
similar, but simplified:
github/rayepps/exobase-js
github/rayepps/exobase-js/settings
github/rayepps/*/*
Using github as an example you'll notice the uri
is very similar to the github url. Thats sort of the idea. In the same way a url is a unique path to a resource, the uri
should be too.
Example Permissions
1import cani from '@exobase/use-authorization/cani' 2import type { PermissionKey } from '@exobase/use-authorization' 3 4const permissions: PermissionKey[] = [ 5 // Basic github user abilities 6 'allow::create::github/repo', 7 'allow::create::github/gist', 8 9 // God mode access to the repos I own 10 'allow::*::github/rayepps/*', 11 'allow::*::github/rayepps/*/settings', 12 13 // Contributor access to some others 14 'allow::contribute::github/vercel/ms', 15 'allow::contribute::github/meta/react', 16 17 // My payment failed so my ability to 18 // create new repos has been taken away 19 // -- overrides the allow above 20 // -- order does not matter 21 'deny::create::github/repo' 22] 23 24const user = cani.user(permissions) 25 26user.has('allow::configure::github/rayepps/exobase-js') // => true 27user.has('allow::configure::github/meta/react') // => true 28user.has('allow::read::github/meta/react/settings') // => false 29user.has('allow::create::github/repo') // => false
This can look very differnet depending on how you implement it. Cani is simple but robust. Your URIs can be as deep or shallow as your use case requires. Your scopes can be as general or as broad as you need.
Props Changes
When using useAuthorization
a service is added called cani
. You can use this to do more permission checks on the user inside your endpoint or deeper (we don't recommend deeper per good design). You can also import the raw cani
function from this module but the one attached to the services in the props has already built the URI prefix trie for the current users specific permission set and won't need to build it again (i.e. it's much faster)
1import { useLambda } from '@exobase/use-lambda' 2import { useTokenAuth, useAuthorization } from '@exobase/hooks' 3import type { Cani } from '@exobase/hooks' 4 5type Services = { 6 cani: Cani 7} 8 9const endpoint = async ({ services }: Props<{}, Services>) => { 10 const { cani } = services 11 if (cani('allow::read::com.github/rayepps/exobase-js/setting')) { 12 return db.settings.read() 13 } 14} 15 16// Using useAuthorization without the `require` 17// option will always pass the authorization check. 18// You can use `cani` in your endpoint to do your 19// own checks. 20export default compose( 21 useLambda(), 22 useTokanAuth('my-little-secret'), 23 useAuthorization({ 24 permissions: ({ auth }) => auth.token.permissions 25 }), 26 endpoint 27)
![Empty State](/_next/static/media/empty.e5fae2e5.png)
No vulnerabilities found.
![Empty State](/_next/static/media/empty.e5fae2e5.png)
No security vulnerabilities found.