# Overview of AuthZ and Delegation specifications Currently the Internet Computer only supports to transfer all authority by delegation. Internet Identity solves the problem partly by scoping the delegation to a particular host. However, there's no general mechanism on the IC to delegate granular capabilities between all forms of identites on the IC. In the following, we'll briefly present common specifications for capabiltiy tokens that allow granular delegation of capabilities, and discuss various aspects regarding the usage on the Internet Computer. In particular, we'll discuss - [UCAN](https://ucan.xyz/) - [CACAO](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-74.md) - [Biscuit](https://www.biscuitsec.org/) ## UCAN User Controlled Authorization Networks (UCANs) are an extension of the popular JSON Web Token (JWT) format specifically designed to enable ways of authorizing offline-first apps and distributed systems. Essentially it includes two new attributes in the JWT payload: * `att`: Capabilities delegated to the audience by the issuer * `prf`: An array of UCAN tokens (or their hashes) from which the capabilites are derived. There needs to be a protocol on how to get the actual tokens based on the hash. Capabilites are defined as objects with the following properties * `with`: Specifies the resource, e.g. a service provided by the canister * `can` : Specicies the ability. For HTTP, this could be `GET`, `POST` .. . Not sure how this would be used for a canister. * `nb` : Optional field that specified additional requierments. See [spec](https://github.com/ucan-wg/spec#241-nb-non-normative-fields) for examples. ### Design Goal Inversion of control: Unlike many authorization systems where a service controls access to resources in their care, location-independent, offline, and leaderless resources require control to live with the user. Therefore, the same data MAY be used across many applications, data stores, and users. ### Example The best way to look at an example is to go to https://ucan.xyz/validator/ #### Header ``` { "alg": "EdDSA", "typ": "JWT", "ucv": "0.8.1" } ``` #### Payload ```` { "iss": "did:key:z6Mkr5aefin1DzjG7MBJ3nsFCsnvHKEvTb2C4YAJwbxt1jFS", "aud": "did:key:z6MkfQhLHBSFMuR7bQXTQeqe5kYUW51HpfZeaymgy1zkP2jM", "nbf": 1529496683, "exp": 9256939505, "att": [ { "with": "wnfs://demouser.fission.name/public/photos/", "can": "wnfs/OVERWRITE" }, { "with": "wnfs://demouser.fission.name/public/notes/", "can": "wnfs/OVERWRITE" } ], "prf": [] } ```` | Field | Type | Description | Required | | ----- | ---------------- | ------------------------------------------- | -------- | | `iss` | `String` | Issuer DID (sender) | Yes | | `aud` | `String` | Audience DID (receiver) | Yes | | `nbf` | `Number` | Not Before UTC Unix Timestamp (valid from) | No | | `exp` | `Number \| null` | Expiration UTC Unix Timestamp (valid until) | Yes | | `nnc` | `String` | Nonce | No | | `fct` | `Json[]` | Facts (asserted, signed data) | No | | `att` | `Json[]` | Attenuations | Yes | | `prf` | `String[]` | Proof of delegation (hash-linked UCANs) | No | ### Revocation The issuer of a UCAN can issue a revocation token. ### Discussion in the context of the IC - `iss` and `aud` would need to be principals encoded as DIDs. - If we'd be using UCANS, should delegation on the IC be implemented as UCANs or should we just include the relevant properties in the data model of the IC delegation? ### Questions - How are UCANs invoked? Does the `aud` need to generate somehow a new token to send to the resource or are the tokens not cryptographically bound to the invoker? ### References - [UCAN Spec](https://github.com/ucan-wg/spec) - [Datalog Playground](https://www.biscuitsec.org/docs/tooling/datalog-playground/) ### Implementations - [TypeScript](https://github.com/ucan-wg/ts-ucan) - [Rust](https://github.com/ucan-wg/rs-ucan) - [Go](https://github.com/ucan-wg/go-ucan) - [Haskell](https://github.com/fission-codes/fission/tree/main/hs-ucan) ## CACAO: Chain-agnostic Capability Object Conceptually very similar to UCANS, but do not allow subdelegation/attenuation. They are represented as [IPLD](https://ipld.io/specs/) documents and use a bit of a different language. ### Design Goal Generalzing ["Sign-in with Ethereum"](https://eips.ethereum.org/EIPS/eip-4361) to provide granular authorization instead of just authentication. ### Structure The payload has the following structure: ``` type Payload struct { domain String // =domain iss String // = DID pkh aud String // =uri version String nonce String iat String // RFC3339 date-time =issued-at nbf optional String // RFC3339 date-time =not-before exp optional String // RFC3339 date-time = expiration-time statement optional String // =statement requestId optional String // =request-id resources optional [ String ] // =resources as URIs } ``` ### Revocation Not mentioned in the specification ### References - [Spec](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-74.md) ### Implementations - [Rust](https://github.com/spruceid/cacao-rs) - [TypeScript](https://github.com/ceramicnetwork/cacao) ## Biscuit Biscuits have been designed for large scale microservices architectures. They are an append only list of blocks which represent caveats. Currently the blocks need to be signed using Ed25519. In comparison to UCANs the most notable difference is that the capabilitites are declared in datalog - a declarative programming language. A relying party, would need to implement an authorizer which includes - facts about the request (current time, resource being accessed, type of the operation) - facts or rules about access control (ACLs, access matrix) - checks to apply some restrictions (every check has to pass for the authorization to succeed) - policies, which are tried in order, the first one to match decides if the authorization passes or fails ### Design Goals - distributed authorization: any node could validate the token only with public information - delegation: a new, valid token can be created from another one by attenuating its rights - avoiding identity and impersonation: in a distributed system, not all services need to know about the token holder's identity. Instead, they care about specific authorizations - capabilities: a request carries a token that contains a set of rights that will be used for authorization, instead of deploying ACLs on every node ### Examples ``` Biscuit { symbols: ["authority", "ambient", "resource", "operation", "right", "current_time", "revocation_id", "user_id"] authority: Block[0] { symbols: ["user_id"] context: "" version: 1 facts: [ user_id("user_1234"), ] rules: [] checks: [] } blocks: [ Block[1] { symbols: ["caveat1", "read"] context: "" version: 1 facts: [] rules: [] checks: [ check if resource("bucket_5678", "/folder1/hello.txt"), operation("read") ] } ] } ``` ### Revocation Biscuit generates unique revocation identifiers for each token, and can provide expiration dates as well, but revocation requires external state management (revocation lists, databases, etc) that is outside of this specification. ### Discussion regarding the IC - Could be implemented on canister-level or a combination of replica and canister. The authorizer and facts would need to be implemented in the canister, but the actual evaluation could happen outside the canister, such that the actual evaluation engine would not need to be redeployed in every canister ### Questions - Could I combine two unrelated base tokens? I think this would be possible in UCAN, but it seems not possbile with Biscuits. ### References - [Website](https://www.biscuitsec.org/) - [Design Doc](https://github.com/biscuit-auth/biscuit/blob/master/DESIGN.md) - [Spec](https://github.com/biscuit-auth/biscuit/blob/master/SPECIFICATIONS.md) - [Examples](https://github.com/biscuit-auth/biscuit/tree/master/samples/v2) - [Summary](https://github.com/biscuit-auth/biscuit/blob/master/SUMMARY.md) ### Implementations - [Rust](https://github.com/biscuit-auth/biscuit-rust) - [WebAssembly](https://github.com/biscuit-auth/biscuit-wasm) - [Java](https://github.com/clevercloud/biscuit-java) - [Haskell](https://github.com/biscuit-auth/biscuit-haskell) ## Concluding thoughts - Obviously, none of the specifications will support Canister signatures out of the box. - We need to think about how important it would be to have uniform design of capabilities that could be used inside the IC and outside the IC. - Attenuation/Caveats with datalog or fixed properties could also be included directly in the delegation data structure we use on the IC - It could make sense to define a few use cases and implement them on cansister level with UCAN and Biscuit to get some experience. Maybe there are others in the working group who'd join this effort.