{ "title": "@chronark/access", "description": "A minimal library for access control. It is designed to be used together with opaque access tokens by providing a simple interface to define roles with different access permissions and verifying requests to resources.", "date": "2022-11-13T00:00:00.000Z", "repository": "chronark/access", "body": { "raw": "A minimal library for access control. It is designed to be used together with opaque access tokens by providing a simple interface to define roles with different access permissions and verifying requests to resources.\n\n- Fully typed\n- Zero dependencies\n- Serializable to store in a database\n\n## Install\n\n```sh-session\nnpm i @chronark/access\n```\n\n## Usage\n\n```ts\nimport { AccessControl, Role } from \"@chronark/access\";\n\n/**\n * Define all your resources and their access patterns\n *\n * key => resource\n * value => array of access types\n */\ntype Statements = {\n user: [\"read\", \"write\", \"dance\"];\n team: [\"read\", \"write\"];\n};\n\n/**\n * Create an access control instance and pass the Statements type to enjoy full\n * type safety\n */\nconst ac = new AccessControl();\n\n/**\n * Now you can define one or more roles by specifying the access permissions\n *\n * This is already fully typed and typescript will let you know if you try to\n * use anything, that is not defined in the Statements type.\n */\nconst role = ac.newRole({\n user: [\"read\", \"write\"],\n team: [\"read\"],\n});\n\n/**\n * Simulate storing and retrieving the role in a database\n *\n * The idea here is, that you can store permissions alongside an API token.\n * Now, when you verify the token, you can also verify the access permissions.\n */\nconst serialized = role.toString();\n\n/**\n * Note how you can pass in the Statements type again, to get full type safety\n */\nconst recovered = Role.fromString(serialized);\n\n/**\n * Validate the role by specifying the resource and the required access\n *\n * everything is fully typed\n */\nconst res = recovered.authorize({\"team\", [\"read\"]});\n\n// res.success => boolean\n// res.error => string | undefined provides a reason for failure\n```", "code": "var Component=(()=>{var h=Object.create;var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var F=(l,e)=>()=>(e||l((e={exports:{}}).exports,e),e.exports),N=(l,e)=>{for(var s in e)a(l,s,{get:e[s],enumerable:!0})},o=(l,e,s,r)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let c of y(e))!m.call(l,c)&&c!==s&&a(l,c,{get:()=>e[c],enumerable:!(r=p(e,c))||r.enumerable});return l};var u=(l,e,s)=>(s=l!=null?h(E(l)):{},o(e||!l||!l.__esModule?a(s,\"default\",{value:l,enumerable:!0}):s,l)),f=l=>o(a({},\"__esModule\",{value:!0}),l);var t=F((v,i)=>{i.exports=_jsx_runtime});var B={};N(B,{default:()=>D,frontmatter:()=>g});var n=u(t()),g={title:\"@chronark/access\",description:\"A minimal library for access control. It is designed to be used together with opaque access tokens by providing a simple interface to define roles with different access permissions and verifying requests to resources.\",repository:\"chronark/access\",date:\"2022-11-13\"};function d(l){let e=Object.assign({p:\"p\",ul:\"ul\",li:\"li\",h2:\"h2\",a:\"a\",span:\"span\",div:\"div\",pre:\"pre\",code:\"code\"},l.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.p,{children:\"A minimal library for access control. It is designed to be used together with opaque access tokens by providing a simple interface to define roles with different access permissions and verifying requests to resources.\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Fully typed\"}),`\n`,(0,n.jsx)(e.li,{children:\"Zero dependencies\"}),`\n`,(0,n.jsx)(e.li,{children:\"Serializable to store in a database\"}),`\n`]}),`\n`,(0,n.jsxs)(e.h2,{id:\"install\",children:[(0,n.jsx)(e.a,{className:\"subheading-anchor\",\"aria-label\":\"Link to section\",href:\"#install\",children:(0,n.jsx)(e.span,{className:\"icon icon-link\"})}),\"Install\"]}),`\n`,(0,n.jsx)(e.div,{\"data-rehype-pretty-code-fragment\":\"\",children:(0,n.jsx)(e.pre,{\"data-language\":\"sh-session\",\"data-theme\":\"default\",children:(0,n.jsx)(e.code,{\"data-language\":\"sh-session\",\"data-theme\":\"default\",children:(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#e1e4e8\"},children:\"npm i @chronark/access\"})})})})}),`\n`,(0,n.jsxs)(e.h2,{id:\"usage\",children:[(0,n.jsx)(e.a,{className:\"subheading-anchor\",\"aria-label\":\"Link to section\",href:\"#usage\",children:(0,n.jsx)(e.span,{className:\"icon icon-link\"})}),\"Usage\"]}),`\n`,(0,n.jsx)(e.div,{\"data-rehype-pretty-code-fragment\":\"\",children:(0,n.jsx)(e.pre,{\"data-language\":\"ts\",\"data-theme\":\"default\",children:(0,n.jsxs)(e.code,{\"data-language\":\"ts\",\"data-theme\":\"default\",children:[(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"import\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" { AccessControl, Role } \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"from\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"@chronark/access\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\";\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Define all your resources and their access patterns\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" *\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * key => resource\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * value => array of access types\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"type\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"Statements\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" {\"})]}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#FFAB70\"},children:\"user\"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\":\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" [\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"read\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\", \"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"write\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\", \"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"dance\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"];\"})]}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#FFAB70\"},children:\"team\"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\":\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" [\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"read\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\", \"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"write\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"];\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"};\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Create an access control instance and pass the Statements type to enjoy full\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * type safety\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"const\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#79B8FF\"},children:\"ac\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"new\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"AccessControl\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"<\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"Statements\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\">();\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Now you can define one or more roles by specifying the access permissions\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" *\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * This is already fully typed and typescript will let you know if you try to\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * use anything, that is not defined in the Statements type.\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"const\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#79B8FF\"},children:\"role\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" ac.\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"newRole\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"({\"})]}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" user: [\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"read\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\", \"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"write\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"],\"})]}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" team: [\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"read\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"],\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"});\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Simulate storing and retrieving the role in a database\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" *\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * The idea here is, that you can store permissions alongside an API token.\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Now, when you verify the token, you can also verify the access permissions.\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"const\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#79B8FF\"},children:\"serialized\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" role.\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"toString\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"();\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Note how you can pass in the Statements type again, to get full type safety\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"const\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#79B8FF\"},children:\"recovered\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" Role.\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"fromString\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"<\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"Statements\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\">(serialized);\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"/**\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * Validate the role by specifying the resource and the required access\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" *\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" * everything is fully typed\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\" */\"})}),`\n`,(0,n.jsxs)(e.span,{className:\"line\",children:[(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"const\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#79B8FF\"},children:\"res\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" \"}),(0,n.jsx)(e.span,{style:{color:\"#F97583\"},children:\"=\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\" recovered.\"}),(0,n.jsx)(e.span,{style:{color:\"#B392F0\"},children:\"authorize\"}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"({\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"team\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\", [\"}),(0,n.jsx)(e.span,{style:{color:\"#9ECBFF\"},children:'\"read\"'}),(0,n.jsx)(e.span,{style:{color:\"#E1E4E8\"},children:\"]});\"})]}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:\" \"}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"// res.success => boolean\"})}),`\n`,(0,n.jsx)(e.span,{className:\"line\",children:(0,n.jsx)(e.span,{style:{color:\"#6A737D\"},children:\"// res.error => string | undefined provides a reason for failure\"})})]})})})]})}function A(l={}){let{wrapper:e}=l.components||{};return e?(0,n.jsx)(e,Object.assign({},l,{children:(0,n.jsx)(d,l)})):d(l)}var D=A;return f(B);})();\n;return Component;" }, "_id": "projects/access.mdx", "_raw": { "sourceFilePath": "projects/access.mdx", "sourceFileName": "access.mdx", "sourceFileDir": "projects", "contentType": "mdx", "flattenedPath": "projects/access" }, "type": "Project", "path": "/projects/access", "slug": "access" }