Esc

    C/C++ SDK

    Native C library with C++ wrapper for InferaDB.

    Coming soon. The C/C++ SDK is under active development. The API surface shown here is based on the Rust SDK and may change before release.

    Native client for InferaDB’s authorization APIs. The C library (inferadb.h) offers a stable ABI suitable for FFI. The C++ wrapper (inferadb.hpp) adds RAII and C++20 idioms. Built on the Rust SDK via cxx for memory safety in the transport layer.

    Requires C11 (C API) or C++20 (C++ wrapper).

    Installation

    vcpkg

    vcpkg install inferadb
    

    CMake (FetchContent)

    include(FetchContent)
    FetchContent_Declare(
      inferadb
      GIT_REPOSITORY https://github.com/inferadb/c.git
      GIT_TAG v0.1.0
    )
    FetchContent_MakeAvailable(inferadb)
    
    target_link_libraries(my_app PRIVATE inferadb::inferadb)
    

    pkg-config (system install)

    pkg-config --cflags --libs inferadb
    

    C API

    Client Initialization

    #include <inferadb.h>
    
    inferadb_client_t *client = NULL;
    inferadb_error_t *err = NULL;
    
    inferadb_config_t config = {
        .url = "https://engine.inferadb.com",
        .auth = {
            .type = INFERADB_AUTH_CLIENT_CREDENTIALS,
            .client_credentials = {
                .client_id = "my-client",
                .private_key_path = "client.pem",
                .certificate_id = "cert-id",
            },
        },
    };
    
    if (inferadb_client_new(&config, &client, &err) != INFERADB_OK) {
        fprintf(stderr, "Failed to connect: %s\n", inferadb_error_message(err));
        inferadb_error_free(err);
        return 1;
    }
    
    /* ... use client ... */
    
    inferadb_client_free(client);
    

    Permission Checks

    inferadb_vault_t *vault = inferadb_vault_open(client, "my-org", "production", &err);
    
    bool allowed = false;
    if (inferadb_check(vault, "user:alice", "can_edit", "document:readme",
                       NULL, &allowed, &err) != INFERADB_OK) {
        fprintf(stderr, "Check failed: %s\n", inferadb_error_message(err));
        inferadb_error_free(err);
    }
    
    if (allowed) {
        /* access granted */
    }
    
    inferadb_vault_free(vault);
    

    With ABAC Context

    inferadb_context_t *ctx = inferadb_context_new();
    inferadb_context_set_string(ctx, "ip_address", "10.0.0.1");
    
    bool allowed = false;
    inferadb_check(vault, "user:alice", "can_view", "document:readme",
                   ctx, &allowed, &err);
    
    inferadb_context_free(ctx);
    

    Batch Check

    inferadb_check_request_t requests[] = {
        { .subject = "user:alice", .permission = "can_edit", .resource = "document:readme" },
        { .subject = "user:bob",   .permission = "can_view", .resource = "document:readme" },
    };
    
    inferadb_check_result_t *results = NULL;
    size_t result_count = 0;
    
    if (inferadb_check_batch(vault, requests, 2, &results, &result_count, &err) != INFERADB_OK) {
        fprintf(stderr, "Batch check failed: %s\n", inferadb_error_message(err));
        inferadb_error_free(err);
    }
    
    for (size_t i = 0; i < result_count; i++) {
        printf("Request %zu: %s\n", i, results[i].allowed ? "allowed" : "denied");
    }
    
    inferadb_check_results_free(results, result_count);
    

    Relationships

    /* Write */
    inferadb_revision_t *token = NULL;
    inferadb_write_relationship(vault,
        "document:readme", "editor", "user:alice",
        &token, &err);
    inferadb_revision_free(token);
    
    /* Delete */
    inferadb_delete_relationship(vault,
        "document:readme", "viewer", "user:bob",
        &err);
    

    Error Handling

    inferadb_error_t *err = NULL;
    bool allowed = false;
    
    if (inferadb_check(vault, "user:alice", "can_edit", "document:readme",
                       NULL, &allowed, &err) != INFERADB_OK) {
        inferadb_error_kind_t kind = inferadb_error_kind(err);
    
        if (inferadb_error_is_retriable(err)) {
            unsigned int retry_after_ms = inferadb_error_retry_after(err);
            /* retry after delay */
        }
    
        inferadb_error_free(err);
    }
    

    Error kinds: INFERADB_ERR_UNAUTHORIZED, INFERADB_ERR_FORBIDDEN, INFERADB_ERR_NOT_FOUND, INFERADB_ERR_RATE_LIMITED, INFERADB_ERR_SCHEMA_VIOLATION, INFERADB_ERR_UNAVAILABLE, INFERADB_ERR_TIMEOUT, INFERADB_ERR_INVALID_ARGUMENT.

    Cleanup

    Every _new/_open has a corresponding _free. Every output parameter that allocates must be freed by the caller.

    Allocator Deallocator
    inferadb_client_new inferadb_client_free
    inferadb_vault_open inferadb_vault_free
    inferadb_context_new inferadb_context_free
    inferadb_revision_* (output) inferadb_revision_free
    inferadb_check_batch (output) inferadb_check_results_free
    inferadb_error_* (output) inferadb_error_free

    C++ API

    RAII resource management, exceptions, and modern C++20 idioms:

    Client Initialization

    #include <inferadb/inferadb.hpp>
    
    auto client = inferadb::Client::builder()
        .url("https://engine.inferadb.com")
        .credentials(inferadb::ClientCredentials{
            .client_id = "my-client",
            .private_key = inferadb::Ed25519PrivateKey::from_pem_file("client.pem"),
            .certificate_id = "cert-id",
        })
        .build();
    

    Permission Checks

    auto vault = client.organization("my-org").vault("production");
    
    // Simple check
    bool allowed = vault.check("user:alice", "can_edit", "document:readme");
    
    // With ABAC context
    auto opts = inferadb::CheckOptions{};
    opts.context["ip_address"] = "10.0.0.1";
    bool allowed = vault.check("user:alice", "can_view", "document:readme", opts);
    
    // Require — throws inferadb::AccessDeniedError
    vault.require("user:alice", "can_edit", "document:readme");
    
    // Batch check
    auto results = vault.check_batch({
        {"user:alice", "can_edit", "document:readme"},
        {"user:bob", "can_view", "document:readme"},
    });
    if (results.all_allowed()) {
        // all checks passed
    }
    

    Relationships

    // Write — returns a revision token
    auto token = vault.relationships().write({
        .resource = "document:readme",
        .relation = "editor",
        .subject = "user:alice",
    });
    
    // Batch write
    vault.relationships().write_batch({
        {"document:readme", "editor", "user:alice"},
        {"document:readme", "viewer", "user:bob"},
    });
    
    // List
    auto rels = vault.relationships().list({.resource = "document:readme"});
    
    // Delete
    vault.relationships().delete_where({
        .resource = "document:readme",
        .relation = "viewer",
        .subject = "user:bob",
    });
    

    Error Handling

    #include <inferadb/inferadb.hpp>
    
    try {
        vault.require("user:alice", "can_edit", "document:readme");
    } catch (const inferadb::AccessDeniedError&) {
        // permission denied
    } catch (const inferadb::Error& e) {
        if (e.is_retriable()) {
            std::this_thread::sleep_for(e.retry_after());
            // retry
        }
        std::cerr << "Error: kind=" << e.kind_name()
                  << " request_id=" << e.request_id() << "\n";
    }
    

    RAII Guarantees

    • inferadb::Client — move-only, closes connection on destruction
    • inferadb::Vault — lightweight handle, safe to copy
    • inferadb::Revision — copyable, movable, comparable

    Testing

    MockClient

    #include <inferadb/testing.hpp>
    
    auto client = inferadb::testing::MockClient::builder()
        .on_check("user:alice", "can_edit", "document:readme").allow()
        .on_check("user:bob", "can_edit", "document:readme").deny()
        .on_check_any_subject("can_view", "document:readme").allow()
        .default_deny()
        .verify_on_destroy(true)
        .build();
    

    InMemoryClient

    auto client = inferadb::testing::InMemoryClient::with_schema_and_data(
        R"(
        type document {
            relation viewer
            relation editor
            relation can_view = viewer | editor
        }
        )",
        {
            {"document:readme", "editor", "user:alice"},
            {"document:readme", "viewer", "user:bob"},
        }
    );
    

    Thread Safety

    • inferadb::Client and inferadb::Vault are thread-safe and shareable
    • C API is thread-safe with per-thread inferadb_vault_t* or external synchronization
    • All inferadb_*_free calls are safe from any thread

    Platform Support

    Platform Architecture Status
    Linux x86_64, aarch64 Supported
    macOS x86_64, arm64 Supported
    Windows x86_64 Supported
    FreeBSD x86_64 Best-effort

    Prebuilt binaries are available for all supported platforms via the GitHub releases page and vcpkg.