Go
The Go version of Biscuit can be found on Github.
Install
In go.mod
:
require(
github.com/biscuit-auth/biscuit-go v1.0.0
)
Create a root key
func CreateKey() (ed25519.PublicKey, ed25519.PrivateKey) {
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)
return publicRoot, privateRoot
}
Create a token
func CreateToken(root *ed25519.PrivateKey) (*biscuit.Biscuit, error) {
builder := biscuit.NewBuilder(*root)
fact, err := parser.FromStringFact(`user("1234")`)
if err != nil {
return nil, fmt.Errorf("failed to parse authority facts: %v", err)
}
err = builder.AddAuthorityFact(fact)
if err != nil {
return nil, fmt.Errorf("failed to add authority facts: %v", err)
}
check, err := parser.FromStringCheck(`check if operation("read")`)
if err != nil {
return nil, fmt.Errorf("failed to parse authority checks: %v", err)
}
err = builder.AddAuthorityCheck(check)
if err != nil {
return nil, fmt.Errorf("failed to add authority checks: %v", err)
}
token, err := builder.Build()
if err != nil {
return nil, fmt.Errorf("failed to build biscuit: %v", err)
}
return token, nil
}
Create an authorizer
func Authorize(token *biscuit.Biscuit, root *ed25519.PublicKey) error {
authorizer, err := token.Authorizer(*root)
if err != nil {
return fmt.Errorf("failed to create authorizer: %v", err)
}
fact1, err := parser.FromStringFact(`resource("/a/file1.txt")`)
if err != nil {
return fmt.Errorf("failed to parse authorizer fact: %v", err)
}
authorizer.AddFact(fact1)
fact2, err := parser.FromStringFact(`operation("read")`)
if err != nil {
return fmt.Errorf("failed to parse authorizer fact: %v", err)
}
authorizer.AddFact(fact2)
policy, err := parser.FromStringPolicy(`allow if resource("/a/file1.txt")`)
if err != nil {
return fmt.Errorf("failed to parse authorizer policy: %v", err)
}
authorizer.AddPolicy(policy)
return authorizer.Authorize()
}
Attenuate a token
func Attenuate(serializedToken []byte, root *ed25519.PublicKey) ([]byte, error) {
token, err := biscuit.Unmarshal(serializedToken)
if err != nil {
return nil, fmt.Errorf("failed to deserialize biscuit: %v", err)
}
blockBuilder := token.CreateBlock()
check, err := parser.FromStringCheck(`check if resource($file), operation($permission), ["read"].contains($permission)`)
if err != nil {
return nil, fmt.Errorf("failed to parse check: %v", err)
}
err = blockBuilder.AddCheck(check)
if err != nil {
return nil, fmt.Errorf("failed to add block check: %v", err)
}
rng := rand.Reader
token2, err := token.Append(rng, blockBuilder.Build())
if err != nil {
return nil, fmt.Errorf("failed to append: %v", err)
}
return token2.Serialize()
}
Seal a token
rng := rand.Reader
return token.Seal(rng)
Reject revoked tokens
The Biscuit::RevocationIds
method returns the list of revocation identifiers as byte arrays.
identifiers := token.RevocationIds();
Query data from the authorizer
The Authorizer::Query
method takes a rule as argument and extract the data from generated facts as tuples.
func Query(authorizer biscuit.Authorizer) (biscuit.FactSet, error) {
rule, err := parser.FromStringRule(`data($name, $id) <- user($name, $id`)
if err != nil {
return nil, fmt.Errorf("failed to parse check: %v", err)
}
return authorizer.Query(rule)
}