| .. | ||
| did | ||
| didcore | ||
| didkey | ||
| README.md | ||
| resolver.go | ||
dids
Table of Contents
Features
did:jwkcreation and resolutiondid:dhtcreation and resoluton- DID Parsing
BearerDIDconcept.BearerDIDimport and export- All did core spec data structures
- singleton DID resolver
Note
This package uses the term
DIDto refer to the string representation e.g.did:ex:1234andBearerDIDto refer to is a composite type that combines a DID with a KeyManager containing keys associated to the DID. Together, these two components form a BearerDID that can be used to sign data.
Note
wtf is a Bearer DID?
BearerDIDis a term i came up with in a state of delirium in order to distinguish between a DID (akadid:ex:moegrammeraka a string) and a DID + a key manager containing private keys associated to the DID. Bearer because..The term "bearer" in the context of identity and access management originates from the concept of "bearer instruments" in financial services. In finance, a bearer instrument is a document that entitles the holder or "bearer" to the rights or assets it represents. The key characteristic of a bearer instrument is that it grants ownership or rights to whoever physically holds it, without necessarily identifying that person.
Applying this concept to the digital realm, particularly in security and authentication, a bearer token functions similarly.
In summary, the term "bearer" in identity and access management is borrowed from the financial concept of bearer instruments, emphasizing the importance of possession in determining access rights or ownership. This parallel underscores the need for careful security measures in the management of bearer tokens in digital systems.
Usage
DID Creation
did:jwk
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/didjwk"
)
func main() {
// Create a new DID
bearerDID, err := didjwk.Create()
if err != nil {
fmt.Printf("Failed to create new DID: %v\n", err)
return
}
fmt.Printf("New DID created: %s\n", bearerDID.URI)
}
Note
if no arguments are provided, uses
LocalKeyManagerby default and usesEd25519to generate key
Providing a custom key manager can be done like so:
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/didjwk"
)
func main() {
km, err := AWSKeyManager()
if err != nil {
fmt.Errorf("failed to initialize AWS Key Manager. %w", err)
}
bearerDID, err := didjwk.Create(KeyManager(km))
if err != nil {
fmt.Printf("Failed to create new DID: %v\n", err)
return
}
fmt.Printf("New DID created: %s\n", bearerDID.URI)
}
Warning
AWSKeyManagerdoesn't exist yet inweb5-gobut will soon
Overriding the default Alogithm ID can be done like so:
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/dsa"
"github.com/beclab/Olares/cli/pkg/web5/didjwk"
)
func main() {
bearerDID, err := didjwk.Create(AlgorithmID(dsa.AlgorithmIDED25519))
if err != nil {
fmt.Printf("Failed to create new DID: %v\n", err)
return
}
fmt.Printf("New DID created: %s\n", bearerDID.URI)
}
Important
Options can be passed in any order and are not mutually exclusive. so you can provide a custom key manager and override the algorithm
did:dht
Warning
TODO: Fill out
did:web
Warning
TODO: Fill out
DID Resolution
this package provides a preconfigured resolver that is capable of resolving all of the did methods included in this module
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/dsa"
"github.com/beclab/Olares/cli/pkg/web5/dids"
)
func main() {
resolutionResult, err := dids.Resolve("did:ex:123")
if err != nil {
fmt.Printf("Failed to resolve DID: %v\n", err)
return
}
}
Importing / Exporting
In scenarios where a Secrets Manager is being used instead of a HSM based KMS, you'll want to:
- create your DID (aka
BearerDID) once, - export it as a
PortableDID - save
PortableDIDin a Secrets Manager, - import the
PortableDIDinto aBearerDIDin order to use it to sign things etc.
Important
this SDK will contain a
cmdto create a DID and output a Portable DID soon!
Exporting
Exporting can be done like so:
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/did"
"github.com/beclab/Olares/cli/pkg/web5/didjwk"
)
func main() {
bearerDID, err := didjwk.Create()
if err != nil {
fmt.Printf("Failed to create new DID: %v\n", err)
return
}
portableDID, _ := bearerDID.ToKeys()
bytes, _ := json.Marshal(&portableDID)
fmt.Println(string(bytes)) // SAVE OUTPUT somewhere safe
}
Warning
bearerDID.ToKeys()will be renamed tobearerDID.ToPortableDID()
Importing
on the flip side, importing a DID can be done like so:
Note
Example assumes Key Material is being passed to process via environment variables
package main
import (
"fmt"
"github.com/beclab/Olares/cli/pkg/web5/did"
)
func main() {
portableDID := os.Getenv("SEC_DID")
bearerDID, err := did.BearerDIDFromKeys(portableDID)
}
Warning
did.BearerDIDFromKeys(portableDID)will be renameddid.FromPortableDID
Development
Directory Structure
dids
├── README.md
├── did
│ ├── bearerdid.go
│ ├── bearerdid_test.go
│ ├── did.go
│ └── did_test.go
├── didcore
│ ├── document.go
│ ├── document_test.go
│ └── resolution.go
├── diddht
│ ├── diddht.go
│ └── diddht_test.go
├── didjwk
│ ├── didjwk.go
│ └── didjwk_test.go
└── resolver.go
| package | description |
|---|---|
did |
contains representations of a DID. |
didcore |
contains all of the data models defined in the DID Core Spec |
did<method> |
one package for each did method |
dids |
high-level APIs that support multiple DID methods |
Rationale
The primary goals for the api surface for dids is to:
- self-contain each did method in its own package in order to provide an api surface that looks like
didjwk.Create(),diddht.Createetc. - provide a
Resolvemethod capable of resolving all did methods in this module without any configuration or registration
The directory/package structure is a result of achieving both goals in a way that hopefully makes logical sense and prevents cyclic imports.
Internal Dependency Diagram:
Adding a new DID Method
- Create a package for the did method being implemented e.g.
didjwk,diddht,didweb
Creation
- Other did methods in this module include a
Createmethod that creates a newBearerDID - Preferrably
Createshould work without having to pass it any arguments - Options should be provided using the functional options pattern described here (thanks for the suggestion @alecthomas)
Resolution
- Implement the [MethodResolver] interface defined in the
didcorepackage - plug the method resolver into
dids/resolver.go
