From 194468b43bdc48655c0fd362de9df306e5b06ec4 Mon Sep 17 00:00:00 2001 From: Daniel Holmgren Date: Tue, 14 Dec 2021 20:49:32 -0600 Subject: [PATCH 1/2] change subject to audience --- example_test.go | 8 ++++---- token.go | 40 ++++++++++++++++++++-------------------- token_test.go | 4 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/example_test.go b/example_test.go index 4c0efc0..0a1716c 100644 --- a/example_test.go +++ b/example_test.go @@ -12,7 +12,7 @@ func Example() { source, err := ucan.NewPrivKeySource(keyOne) panicIfError(err) - subjectDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic()) + audienceDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic()) panicIfError(err) caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE") @@ -23,7 +23,7 @@ func Example() { zero := time.Time{} // create a root UCAN - origin, err := source.NewOriginToken(subjectDID, att, nil, zero, zero) + origin, err := source.NewOriginToken(audienceDID, att, nil, zero, zero) panicIfError(err) id, err := origin.CID() @@ -35,7 +35,7 @@ func Example() { {caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("dataset", "third:resource")}, } - if _, err = source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero); err != nil { + if _, err = source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero); err != nil { fmt.Println(err) } @@ -43,7 +43,7 @@ func Example() { {caps.Cap("OVERWRITE"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")}, } - derivedToken, err := source.NewAttenuatedToken(origin, subjectDID, att, nil, zero, zero) + derivedToken, err := source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero) panicIfError(err) id, err = derivedToken.CID() diff --git a/token.go b/token.go index 265f50d..cab82cc 100644 --- a/token.go +++ b/token.go @@ -46,9 +46,9 @@ const ( // token a UCAN type Token struct { // Entire UCAN as a signed JWT string - Raw string - Issuer didkey.ID - Subject didkey.ID + Raw string + Issuer didkey.ID + Audience didkey.ID // the "inputs" to this token, a chain UCAN tokens with broader scopes & // deadlines than this token Proofs []Proof `json:"prf,omitempty"` @@ -118,8 +118,8 @@ type CIDBytesResolver interface { // implementations of Source must conform to the assertion test defined in the // spec subpackage type Source interface { - NewOriginToken(subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) - NewAttenuatedToken(parent *Token, subjectDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) + NewOriginToken(audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) + NewAttenuatedToken(parent *Token, audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) } type pkSource struct { @@ -196,24 +196,24 @@ func NewPrivKeySource(privKey crypto.PrivKey) (Source, error) { }, nil } -func (a *pkSource) NewOriginToken(subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { - return a.newToken(subjectDID, nil, att, fct, nbf, exp) +func (a *pkSource) NewOriginToken(audienceDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { + return a.newToken(audienceDID, nil, att, fct, nbf, exp) } -func (a *pkSource) NewAttenuatedToken(parent *Token, subjectDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { +func (a *pkSource) NewAttenuatedToken(parent *Token, audienceDID string, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { if !parent.Attenuations.Contains(att) { return nil, fmt.Errorf("scope of ucan attenuations must be less than it's parent") } - return a.newToken(subjectDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp) + return a.newToken(audienceDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp) } // CreateToken returns a new JWT token -func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { +func (a *pkSource) newToken(audienceDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*Token, error) { // create a signer for rsa 256 t := jwt.New(a.signingMethod) - // if _, err := did.Parse(subjectDID); err != nil { - // return nil, fmt.Errorf("invalid subject DID: %w", err) + // if _, err := did.Parse(audienceDID); err != nil { + // return nil, fmt.Errorf("invalid audience DID: %w", err) // } t.Header[UCANVersionKey] = UCANVersion @@ -234,7 +234,7 @@ func (a *pkSource) newToken(subjectDID string, prf []Proof, att Attenuations, fc t.Claims = &Claims{ StandardClaims: &jwt.StandardClaims{ Issuer: a.issuerDID, - Subject: subjectDID, + Audience: audienceDID, NotBefore: nbfUnix, // set the expire time // see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4 @@ -317,7 +317,7 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok var iss didkey.ID // TODO(b5): we're double parsing here b/c the jwt lib we're using doesn't expose - // an API (that I know of) for storing parsed issuer / subjects + // an API (that I know of) for storing parsed issuer / audience if issStr, ok := mc["iss"].(string); ok { iss, err = didkey.Parse(issStr) if err != nil { @@ -327,16 +327,16 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok return nil, fmt.Errorf(`"iss" key is not in claims`) } - var sub didkey.ID + var aud didkey.ID // TODO(b5): we're double parsing here b/c the jwt lib we're using doesn't expose - // an API (that I know of) for storing parsed issuer / subjects - if subStr, ok := mc["sub"].(string); ok { - sub, err = didkey.Parse(subStr) + // an API (that I know of) for storing parsed issuer / audience + if audStr, ok := mc["aud"].(string); ok { + aud, err = didkey.Parse(audStr) if err != nil { return nil, err } } else { - return nil, fmt.Errorf(`"sub" key is not in claims`) + return nil, fmt.Errorf(`"aud" key is not in claims`) } var att Attenuations @@ -372,7 +372,7 @@ func (p *TokenParser) parseAndVerify(ctx context.Context, raw string, child *Tok return &Token{ Raw: raw, Issuer: iss, - Subject: sub, + Audience: aud, Attenuations: att, Proofs: prf, }, nil diff --git a/token_test.go b/token_test.go index 8d9bda0..00ca386 100644 --- a/token_test.go +++ b/token_test.go @@ -101,7 +101,7 @@ func TestED25519PrivKeySource(t *testing.T) { t.Fatal(err) } - subjectDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic()) + audienceDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic()) if err != nil { panic(err) } @@ -109,7 +109,7 @@ func TestED25519PrivKeySource(t *testing.T) { zero := time.Time{} // create a root UCAN - origin, err := source.NewOriginToken(subjectDID, nil, nil, zero, zero) + origin, err := source.NewOriginToken(audienceDID, nil, nil, zero, zero) if err != nil { panic(err) } From d8e8a57e63af3c66f0db789cc5551b631718e2c5 Mon Sep 17 00:00:00 2001 From: Justin Johnson Date: Sat, 26 Mar 2022 06:22:15 -0500 Subject: [PATCH 2/2] Fix tests --- example_test.go | 4 ++-- token_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example_test.go b/example_test.go index 0a1716c..73d6e23 100644 --- a/example_test.go +++ b/example_test.go @@ -58,9 +58,9 @@ func Example() { fmt.Printf("issuer DID key type: %s\n", tok.Issuer.Type().String()) // Output: - // cid of root UCAN: bafkreid6l4npxfwei2ccpelqkhirthcaa2lpmg3xa4rz4lrsqz2rgujp5m + // cid of root UCAN: bafkreihl4b2ncrijeutlkppykgspz6wm3q2o4wiej6njl6tj7k2xa3zcue // scope of ucan attenuations must be less than it's parent - // cid of derived UCAN: bafkreibeirwwbnz2cmboq5t47d3rsjxrd4rcnreptuozwcc2lr3pbnzuki + // cid of derived UCAN: bafkreifhpoxctmbmvocdevfbmio6cpzltwauesyyjycipnylocoykwghzu // issuer DID key type: RSA } diff --git a/token_test.go b/token_test.go index 00ca386..63b4e29 100644 --- a/token_test.go +++ b/token_test.go @@ -62,7 +62,7 @@ func TestPrivKeySource(t *testing.T) { t.Fatal(err) } - expect := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJzdWIiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ndbCaw73SX-cmGz0tQq16nsQsp3Thw1lyza_W8juvoemGo5aiT-ayOSvgl4oeShoBfBiz7NQ7T6FUDfpiUF8cwfP2WLbW-TXDan9arTKw_KLZ3j-re5ACFRVKDWy6sSfJ1BncX9ADt2nmistxYc5uE4wO0RPl9ulSjWsL4mVq6pf77ajPehUYvDgSerGzcvNOmxibDC760gb-F_2jijnA-TEwYvitFaZ_3MmmKhUiMuPP_XqYVWnmuNhje-N1yQg_tEJCsuj25zqFefW9jLPnvkywgyrPyMcrXj1ZQMCX9n37TQbC2WUZE7KvuBkuK11dAkrtXkBH-Gr9QiDWLsdPw` + expect := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJhdWQiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ggJJ8fovwKVbq_hLb0sVKlvkFRcKJWb-55RgIagjzO9D9I0pZ5g3elkOCkf1XA60_32fE-K_Dj97np6-BQx_F5u_PofYi6C0BYfR4YATA5jzymT7nBLrdOzhr0Vh2FChYoyM82CT4tkOGSlnvaoCgB4OLMOzlvpWmbfRi5GB3d6yAfdhBGsDuAJ9L7V_N5WBFpjarSu2xAYhVUhFM8IbILHMipXWRd2sP-_DzxmsneS7qu9fxAk35DDC_8cONPp1ZrFUw-VhGts0jYOVuExl_ZWqE3y2XJLtiperxFWO45q59WdULrn15ciQjRhn2O-QmXHmOxLNZMCI6lbFFiCHWg` if expect != root.Raw { t.Errorf("token mismatch. expected: %q.\ngot: %q", expect, root.Raw) } @@ -77,7 +77,7 @@ func TestPrivKeySource(t *testing.T) { } cidStr := mustCidString(t, derivedToken) - expectCID := "bafkreibeirwwbnz2cmboq5t47d3rsjxrd4rcnreptuozwcc2lr3pbnzuki" + expectCID := "bafkreifhpoxctmbmvocdevfbmio6cpzltwauesyyjycipnylocoykwghzu" if expectCID != cidStr { t.Errorf("derived token CID mismatch. expected: %q.\ngot: %q", expectCID, cidStr) @@ -130,7 +130,7 @@ func TestTokenSource(t *testing.T) { } func TestTokenParse(t *testing.T) { - raw := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJzdWIiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ndbCaw73SX-cmGz0tQq16nsQsp3Thw1lyza_W8juvoemGo5aiT-ayOSvgl4oeShoBfBiz7NQ7T6FUDfpiUF8cwfP2WLbW-TXDan9arTKw_KLZ3j-re5ACFRVKDWy6sSfJ1BncX9ADt2nmistxYc5uE4wO0RPl9ulSjWsL4mVq6pf77ajPehUYvDgSerGzcvNOmxibDC760gb-F_2jijnA-TEwYvitFaZ_3MmmKhUiMuPP_XqYVWnmuNhje-N1yQg_tEJCsuj25zqFefW9jLPnvkywgyrPyMcrXj1ZQMCX9n37TQbC2WUZE7KvuBkuK11dAkrtXkBH-Gr9QiDWLsdPw` + raw := `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVjdiI6IjAuNy4wIn0.eyJhdWQiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJpc3MiOiJkaWQ6a2V5OnoyTUd3NGdrODRVU290YVdmNEFrSjgzRGNucmZnR2FjZUY4NktRWFJZTWZRN3hxblVGRVREN3RGNGprTkd2QUV0dlZ6Rm5RdTkydEZ3ZkNyb2ZWZ0c2WnkyZVlKZURSckVVZ1c5WXZCazJXSHVUUnJFZ0FTZnBxR2tKUkdnR3FiNmNidjFxR2N2Nm1FSFF5YlR5M2JOeXFxd3VRWXA3c3BuSlFObVJhUGk0Z3F1czVEWnVOc2NRZjFSMXhCdVN6WHk1YnNCaFlSZzdFcDZmNkJad0U2cHZCamt5ellqWERVYlF2a0VpeG0zcHR3RTRnZ2VZU21oUXFxbU1ac1lwcG1lY1VFMjhuTTdFekx2Q3hRZEZ1QndXZ2U3QURVYzdxVGYxeXNpUzl1YXdOTnA1aER2aHl2cXRDaWg3a3FvTHVzTGVnd2pHZTJTcDhDcUZmdUNRNWgxdHh4WHozdEdtRGZEUDE3Nm15R1htc3R0eDV5MjVTOXpwejg1ZEc4WnRrRnZ4bXNjOFltaXZlRUMycWFkY2FrWEoiLCJhdHQiOlt7ImFwaSI6IioiLCJjYXAiOiJTVVBFUl9VU0VSIn0seyJjYXAiOiJTVVBFUl9VU0VSIiwiZGF0YXNldCI6ImI1OndvcmxkX2JhbmtfcG9wdWxhdGlvbjoqIn1dfQ.ggJJ8fovwKVbq_hLb0sVKlvkFRcKJWb-55RgIagjzO9D9I0pZ5g3elkOCkf1XA60_32fE-K_Dj97np6-BQx_F5u_PofYi6C0BYfR4YATA5jzymT7nBLrdOzhr0Vh2FChYoyM82CT4tkOGSlnvaoCgB4OLMOzlvpWmbfRi5GB3d6yAfdhBGsDuAJ9L7V_N5WBFpjarSu2xAYhVUhFM8IbILHMipXWRd2sP-_DzxmsneS7qu9fxAk35DDC_8cONPp1ZrFUw-VhGts0jYOVuExl_ZWqE3y2XJLtiperxFWO45q59WdULrn15ciQjRhn2O-QmXHmOxLNZMCI6lbFFiCHWg` caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE")