# UCAN State
This is further thinkng on the subject of attaching extra info to the UCANs. In web3.storage we use define [authorization session] which is a fancy signature & an attestation that web3.storage has performed a validation of that chain and concluded it be sound.
In the example below we see a UCAN delegation where Alice delegates `store/*` capability to the new `did:key:zAlice` agent with her email address. It also supplies the proof that shows that `did:key:zAlice` has delegated access to the `space://did:key:zAlice` Alice's email address which it redelegates
```json
{
"iss": "mailto:alice@web.mail",
"aud": "did:key:z6MktafZTREjJkvV5mfJxcLpNBoVPwDLhTuMg9ng7dY4zMAL",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [{
"iss": "did:key:z6Mkk89bC3JrVqKie71YEcc5M1SMVxuCgNx6zLZ8SYJsxALi",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "ucan:*",
"can": "*",
}]
}]
}
```
## ⚠️ No Signatures
There is no clear way for `mailto:alice@web.mail` to sign that UCAN.
> There are some ideas around using DKIM signatures, but they are some UX challenges to overcome before it can go mainstream.
## 💡 Interactive Validation
Perhaps it is ok to leave out signature in the above example and initiate interactive authorization flow instead. Depending on the context we could either render UI for the user so they could complete authorization or send an email to `alice:web.mail` so that Alice could confirm delegation.
However we do not want to start interactive authorization flow every time we encounter such delegation.
Ideally we'd perform interactive flow once and encode authorization in a verifiable proof which we can hand back to the authorized agent, so they can supply it in the future calls avoiding subsequent authorizations.
## 🚢 Current solution
As per [authorization session] spec we record authorization proof in UCAN delegation from `web3.storage` to `mailto:alice@web.mail` and our original example turns into
```json
{
"iss": "mailto:alice@web.mail",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [
{
"iss": "did:key:zAlice",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "space://did:key:zAlice",
"can": "*",
}]
},
{
"iss": "did:web:web3.storage",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "did:web:web3.storage",
"can": "./update",
"nb": {
"permit": {
"iss": "mailto:alice@web.mail",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}]
}
}
}]
}
]
}
```
ℹ️ So we basically took the outer UCAN wrapped it in the `./update` capability which we delegated back to `mailto:alice@web.mail` so we could stick back into the outer UCAN.
This introduces a lot of incidental complexity in an attempt to align principals in linear proof chain. However we're already thinking to drop linear proof chain requirement, so perhaps we remove some of the complexity with it.
So let's step back, all we really want is for `web3.storage` to state that it checked outer UCAN and it concluded it to be valid.
💭 Here is an interesting thought when validator checks specific proof chain and concludes it to be valid it can cache that conclusion and avoid revalidating same proof chain again. However today it needs to store that conclusion localy.
💡 What we've been trying to accomplish is essentially passing that cache back to the agent so it could send it along with the UCAN next time around.
✨ This is really powerful idea, not only this can speed up validation it can also help us trim proof chains saved & send around. Agent could just replace chain of proofs with a proof of validation.
## ⚡️ UCAN Cash
Here is idea, how about we define special `ucan/authorize` capability that can be used to mark any proof "authorized" and tell validator to basically skip validation
```json
{
"iss": "did:key:zAgent",
"aud": "did:web:web3.storage",
"att": [
{
"with": "space://did:key:zAlice",
"can": "store/add"
}
],
"prf": [
{
"iss": "mailto:alice@web.mail",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [
{
"iss": "did:key:zAlice",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "space://did:key:zAlice",
"can": "*",
}]
}
]
},
{
"iss": "did:web:web3.storage",
"aud": "ucan:proof_cid",
"att": [{
"can": "ucan/authorize",
"with": "did:web3.storage"
}]
}
]
}
```
Ok above is cool but what we really want is to have some way to drop-in replacement in the actual UCAN so maybe instead we could add another field that does not participate in signatures allowing use to do this instead
```json
{
"iss": "mailto:alice@web.mail",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [{
"iss": "did:key:zAlice",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "space://did:key:zAlice",
"can": "*",
}]
}],
"auth": [
{
"iss": "did:web:web3.storage",
"aud": "ucan:proof_cid",
"att": [{
"can": "ucan/authorize",
"with": "did:web3.storage"
}]
}
]
}
```
Obove proof_cid would be of the same outer UCAN without `auth` field.
---
Maybe we can borrow idea from the [`Authorization`](https://github.com/ucan-wg/invocation/#4-authorization) used in UCAN Invocation spec.
```json
{
"iss": "did:key:zSomeKey",
"aud": "did:web3.storage",
"att": [
{
"can": "ucan/authorize",
"with": "ucan:proof_cid"
}
],
"prf": [
{
"iss": "did:web3.storage",
"aud": "did:key:zSomeKey",
"att": [{
"can": "ucan/authorize",
"with": "ucan:*"
}]
}
]
}
```
```json
{
// this is silly but no other way to tie two proofs together
"iss": "did:key:zAgent",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [
{ // bafy...proof
"iss": "mailto:alice@web.mail",
"aud": "did:key:zAgent",
"att": [{
"with": "space://did:key:zAlice",
"can": "store/*"
}],
"prf": [{
"iss": "did:key:zAlice",
"aud": "mailto:alice@web.mail",
"att": [{
"with": "space://did:key:zAlice",
"can": "*",
}]
}],
},
{
"iss": "did:key:zSomeKey",
"aud": "did:key:zAgent",
"att": [
{
"with": "did:web:web3.storage"
"can": "ucan/authorize",
"nb": { "permit": { "/": "bafy...proof" } }
}
],
"prf": [
{
"iss": "did:web3.storage",
"aud": "did:key:zSomeKey",
"att": [{
"can": "ucan/authorize",
"with": "did:web:web3.storage"
}]
}
]
}
]
}
```
[authorization session]:https://github.com/web3-storage/specs/blob/feat/non-sudo-auth/w3-session.md#authorization-session
{"metaMigratedAt":"2023-06-17T21:02:18.076Z","metaMigratedFrom":"Content","title":"UCAN State","breaks":true,"contributors":"[{\"id\":\"fff58d5d-df29-4dd3-93ef-42fd0194a26f\",\"add\":8887,\"del\":1528}]"}