{"id":13523084,"url":"https://github.com/domwoe/access_control","last_synced_at":"2025-09-02T16:59:46.825Z","repository":{"id":65438923,"uuid":"592015285","full_name":"domwoe/access_control","owner":"domwoe","description":"Demonstration of access control patterns on the Internet Computer","archived":false,"fork":false,"pushed_at":"2023-01-27T16:43:39.000Z","size":4115,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-02T07:33:34.634Z","etag":null,"topics":["access-control","certified-variables","demo-app","internet-computer","permission-management","proof-of-concept"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/domwoe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2023-01-22T17:05:57.000Z","updated_at":"2024-10-06T17:42:55.000Z","dependencies_parsed_at":"2023-02-13T00:45:30.354Z","dependency_job_id":null,"html_url":"https://github.com/domwoe/access_control","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/domwoe/access_control","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domwoe%2Faccess_control","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domwoe%2Faccess_control/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domwoe%2Faccess_control/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domwoe%2Faccess_control/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/domwoe","download_url":"https://codeload.github.com/domwoe/access_control/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domwoe%2Faccess_control/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273317747,"owners_count":25084037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-02T02:00:09.530Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","certified-variables","demo-app","internet-computer","permission-management","proof-of-concept"],"created_at":"2024-08-01T06:00:55.313Z","updated_at":"2025-09-02T16:59:46.793Z","avatar_url":"https://github.com/domwoe.png","language":"Rust","funding_links":[],"categories":["Courses, Tutorials, and Samples"],"sub_categories":["Tutorials and Samples"],"readme":"# Access Control on the Internet Computer\n\n![heimdall](./assets/heimdall_access_control.png)\n\n\n**Note:** This is a demonstration project and hasn't been audited. Please use it for inspiration only.\n\n## Motivation \u0026 Goal\n\nThe Internet Computer has a built-in mechanism for access control based on cryptographic signatures. The canister can be sure that its method was called by a specific principal, which is available as `ic_cdk::api::caller()`. However, the canister needs also to know which permissions this principal has.\n\nIn microservice architectures, it's common to centralize access control by having a single authorization service that manages all permissions. This simplifies permission management but raises the question of how resource services learn about permissions. There are two main patterns:\n\n1) **Tokens**: A client requests an authorization token from the authorization service and invokes it at the resource service. Here, the resource service does not need to directly communicate with the authorization service.\n2) **Validation endpoint (Inter-canister call)**: The authorization server exposes a validation endpoint that the resource service can use to validate permissions.\n\nOn the Internet Computer, we can use the same patterns. This demonstration project showcases both patterns and provides a [comparison](#comparison).\n\n## Architecture\n\nWe have the following two canisters:\n\n### Authorization Canister\n\nThe authorization canister has the following interface:\n\n```\ntype token = blob;\ntype target = text;\nservice : {\n    \"update_permissions\": (principal, target, bool) -\u003e (text); // update permissions of a specific user and target (by its function name)\n    \"read_permissions_certified\": ()              -\u003e (opt token) query; // fetch permissions as token\n    \"verify_permissions\": (principal, target)       -\u003e (bool, nat) query; // verify permissions\n}\n```\n\nThe permissions are maintained in a certified data structure using the `ic-certified-map` crate and the [certified data](https://internetcomputer.org/how-it-works/response-certification/) functionality of the Internet Computer. When a client fetches the token with the `read_permissions_certified` function, then this token includes a path to the state root hash of the Internet Computer signed by the subnet together with a delegation from the NNS subnet. Thereby, the resource canister can verify the authenticity of the token given the IC's public key and the client can't tamper with the token.\nThe token also includes a timestamp to validate freshness. \n \n\n### Resource canister\n\nThe resource canister is the [counter example canister](https://github.com/dfinity/examples/tree/master/rust/counter) with added permissions.\n\n```\ntype token = blob;\nservice : (principal) -\u003e {\n    \"get\": (opt token)      -\u003e (nat, nat) query;\n    \"get_composite\": (opt blob) -\u003e (nat, nat) query;\n    \"set\": (nat, opt token) -\u003e (nat);\n    \"inc\": (opt token)      -\u003e (nat);\n```\n\nThe second number in the return values of the first two methods and the number in the return values of the last two methods is the number of instructions used for the verification of the permissions.\n\nNote that we have to provide a principal as an init argument. This allows registering the authorization canister. We need the principal of the authorization canister to verify that the tokens have been \"signed\" by the authorization canister, or to know how to call the `verify_permissions` endpoints.\n\nFurthermore, we note that each endpoint has an optional argument to provide the authorization token and that there's an additional endpoint called `get_composite`. This is a composite query that allows performing an inter-canister query call to the `verify_permissions` endpoint.\n\n\n### Patterns\n\n#### Token-based access control\n\n![Token-based access control](./assets/access_control_token.png)\n\n#### Validation endpoint (Inter-canister call)\n\n![Validation endpoint](./assets/access_control_intercanister.png)\n\n## Comparison\n\n\n|          |           Token          |       Inter-canister Call      |\n|----------|--------------------------|--------------------------------|\n| DevX     |  :thinking:\t          |       :grinning:\t           |\n| Latency  |  :grinning:\t          |       :grinning: (same subnet) |\n| Cost     |  :goberserk:             |    :slightly_smiling_face:   |\n| Security |  :grinning:              |       :grinning:               |\n\n### Developer Experience\n\nThe token-based approach adds quite a bit of complexity. As a client, we need to fetch the authorization token and have logic to get a new one if it is expired. Furthermore, there we need to verify the permissions in the certified map, as well as verify the IC certificate. This could be abstracted away in a library though. The token-based approach is also currently out of reach for Motoko developers, since we don't have a library for a certified map, as well as a library for BLS signature verification.\n\nThe inter-canister call to the validation endpoint, on the other hand, is very easy to implement in Rust and Motoko.\n\n### Latency \u0026 Cost\n\nAs long as both canisters are on the same subnet there is no big difference in latency between the two approaches. With the availability of composite queries, it could be even faster to have a composite query than to do the token verification.\nIf the canisters were on different subnets, then the token-based approach would provide lower latency.\n\nOn the cost side, let's look at the token approach first: \n- Token size: 221 bytes\n- Ingress msg byte cost: 1'000 * 221 = 221'000 cycles (we don't need to take the cost for the ingress message itself into account, since it is needed for both approaches)\n- Instructions for certificate verification: 463'975'738 ~\u003e 185'590'000 cycles\n\nTotal: 185'811'000 cycles\n\nFor the inter-canister call approach, we have a call and a reply, which cost 260'000 cycles each + 3 times the cost for update message execution of 590'000 cycles =\u003e 2'290'000 cycles.\nThe data transferred is rather small, so we neglect this cost hee.\n\nThe instructions used for verification of the permissions by the authorization canister are also quite small with about 50'000 instructions =\u003e 20000 cycles\n\nTotal: 2'310'000 cycles\n\n=\u003e The token-based approach is approx. 80 times as expensive as the inter-canister call-based approach.\n\nNote: You can find the detailed list of all costs on the IC [here](https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs). I've assumed a normal application subnet with 13 nodes.\n\n### Security\n\n There are two points to mention concerning security:\n 1) The inter-canister call approach has the advantage that permissions can immediately be revoked (if there's no caching).\n 2) You need to be aware of the implications of inter-canister calls in general. See the relevant section in the [Security Best Practices](https://internetcomputer.org/docs/current/references/security/rust-canister-development-security-best-practices#inter-canister-calls-and-rollbacks).\n\n## Demo\n\n### Prerequisites\n\nYou need to have the command line tool `dfx` installed:\n\n\n```\nsh -ci \"$(curl -fsSL https://internetcomputer.org/install.sh)\"\n\n```\n\n### Local demo\n\nYou can run a demo flow that will deploy the canisters, set some permissions, fetch a token and perform some operations on the resource canister with and without the authorization token. Furthermore, the runtime of the operations will be written to the terminal.\n\nYou can run the demo flow with the following command:\n\n```\n./demo.sh\n```\n\n### Live deployment\n\nI've deployed the canisters to the IC on a single subnet. You can interact with the deployed canisters:\n\n```\nResource canister: 62hqk-naaaa-aaaap-qa5oa-cai\nAuthorization canister: 65gw6-ayaaa-aaaap-qa5oq-cai\n```\nor deploy your own instances.\n\nSome example calls (or a complete flow) can be found in [`demo_ic.sh`](/demo_ic.sh).\n\n\n## Final Remarks\n\nThe authorization canister does not use stable memory, as such all permissions are lost on upgrade.\n\n\n## What's next?\n\nIf you want to work on production-ready libraries or a configurable authorization canister, then get in contact with me or apply for a [DFINITY Developer Grant](https://dfinity.org/grants).\n\n## You don't know about the Internet Computer?\n\nCheck out [https://internetcomputer.org](https://internetcomputer.org).\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdomwoe%2Faccess_control","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdomwoe%2Faccess_control","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdomwoe%2Faccess_control/lists"}