A persistent adapter for Casbin that uses ArangoDB as the storage backend. Store your authorization policies in ArangoDB instead of flat files, with support for clusters, TLS, and flexible configuration.
ArangoDB is a multi-model database that excels at storing graph data, documents, and key-value pairs. If you're already using ArangoDB or need the flexibility it provides, this adapter makes it easy to persist Casbin policies there.
- ✅ Simple configuration - Functional options pattern for easy setup
- ✅ TLS support - Secure connections with custom certificate configuration
- ✅ Cluster support - Multiple endpoints with round-robin load balancing
- ✅ Auto-creation - Automatically creates database and collection if they don't exist
- ✅ Thread-safe - Safe for concurrent use
- ✅ Context-aware - All major operations support context for timeouts and cancellation
- ✅ Backward compatible - Still supports direct client usage if needed
go get github.com/denisbytes/arango-adapterpackage main
import (
"log"
arangoadapter "github.com/denisbytes/arango-adapter"
"github.com/casbin/casbin/v2"
)
func main() {
// Create adapter with simple configuration
adapter, err := arangoadapter.NewAdapter(
arangoadapter.WithEndpoints("http://localhost:8529"),
arangoadapter.WithAuthentication("root", "password"),
arangoadapter.WithDatabase("casbin"),
arangoadapter.WithCollection("casbin_rule"),
)
if err != nil {
log.Fatal(err)
}
// Create the enforcer
enforcer, err := casbin.NewEnforcer("model.conf", adapter)
if err != nil {
log.Fatal(err)
}
// Use Casbin as normal
enforcer.AddPolicy("alice", "data1", "read")
enforcer.SavePolicy()
}The adapter uses the functional options pattern for flexible configuration:
// Set ArangoDB endpoints (single server or cluster)
WithEndpoints("http://localhost:8529")
// Set authentication
WithAuthentication("username", "password")
// Set database name (default: "casbin")
WithDatabase("my_database")
// Set collection name (default: "casbin_rule")
WithCollection("my_collection")// Enable TLS with a CA certificate file
adapter, err := arangoadapter.NewAdapter(
arangoadapter.WithEndpoints("https://localhost:8529"),
arangoadapter.WithAuthentication("root", "password"),
arangoadapter.WithTLS("/path/to/ca-cert.pem"),
)Or use a custom TLS configuration:
import (
"crypto/tls"
"crypto/x509"
"os"
)
// Load your certificates
caCert, _ := os.ReadFile("/path/to/ca-cert.pem")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: caCertPool,
}
adapter, err := arangoadapter.NewAdapter(
arangoadapter.WithEndpoints("https://localhost:8529"),
arangoadapter.WithAuthentication("root", "password"),
arangoadapter.WithTLSConfig(tlsConfig),
)// Connect to an ArangoDB cluster with multiple coordinators
adapter, err := arangoadapter.NewAdapter(
arangoadapter.WithEndpoints(
"http://coordinator1:8529",
"http://coordinator2:8529",
"http://coordinator3:8529",
),
arangoadapter.WithAuthentication("root", "password"),
)The adapter uses round-robin load balancing across all endpoints.
If you already have an ArangoDB client configured, you can use it directly:
import (
"github.com/arangodb/go-driver/v2/arangodb"
"github.com/arangodb/go-driver/v2/connection"
)
// Your existing client setup
endpoint := connection.NewRoundRobinEndpoints([]string{"http://localhost:8529"})
config := connection.DefaultHTTP2ConfigurationWrapper(endpoint, false)
config.Authentication = connection.NewBasicAuth("root", "password")
conn := connection.NewHttp2Connection(config)
client := arangodb.NewClient(conn)
// Create adapter from existing client
adapter, err := arangoadapter.NewAdapterFromClient(client, "casbin", "casbin_rule")The adapter implements all required Casbin interfaces:
LoadPolicy(model)- Load all policies from databaseLoadPolicyCtx(ctx, model)- Load with context supportSavePolicy(model)- Save all policies (replaces existing)SavePolicyCtx(ctx, model)- Save with context support
AddPolicy(sec, ptype, rule)- Add a single policyAddPolicyCtx(ctx, sec, ptype, rule)- Add with contextRemovePolicy(sec, ptype, rule)- Remove a single policyRemovePolicyCtx(ctx, sec, ptype, rule)- Remove with contextUpdatePolicy(sec, ptype, oldRule, newRule)- Update a policy
AddPolicies(sec, ptype, rules)- Add multiple policiesRemovePolicies(sec, ptype, rules)- Remove multiple policiesUpdatePolicies(sec, ptype, oldRules, newRules)- Update multiple policies
RemoveFilteredPolicy(sec, ptype, fieldIndex, fieldValues...)- Remove policies matching a filterRemoveFilteredPolicyCtx(ctx, sec, ptype, fieldIndex, fieldValues...)- Remove with contextUpdateFilteredPolicies(sec, ptype, newPolicies, fieldIndex, fieldValues...)- Update policies matching a filter
Policies are stored as documents in ArangoDB:
{
"_key": "auto-generated-by-arangodb",
"ptype": "p",
"v0": "alice",
"v1": "data1",
"v2": "read",
"v3": "",
"v4": "",
"v5": ""
}ptype: Policy type (p, g, p2, g2, etc.)v0-v5: Up to 6 values per rule (Casbin's limit)
Here's a simple RBAC model:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.actSave this as model.conf and you're ready to go.
Need a quick ArangoDB instance for testing?
docker run -e ARANGO_ROOT_PASSWORD=password -p 8529:8529 arangodb/arangodb:latestThen connect to http://localhost:8529 with username root and password password.
Check out the examples directory for more:
- basic - Simple usage with RBAC
- tls - Secure connection with TLS
- cluster - Multi-coordinator cluster setup
- Use batch operations -
AddPolicies()is much faster than multipleAddPolicy()calls - Use context timeouts - Always set reasonable timeouts with the
*Ctx()methods - Consider indexes - For large policy sets, add indexes on
ptypeand frequently queriedv*fields in ArangoDB
The adapter uses a mutex to protect concurrent writes, so it's safe to use from multiple goroutines.
MIT License - see LICENSE file for details.
Found a bug or want to add a feature? Pull requests are welcome!
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Casbin - The authorization library this adapter works with
- ArangoDB Go Driver - Official Go driver for ArangoDB