Radikant-Pocketbase-C

database 🗄️ driver

Device Screen

Pocketbase is a interresting project that can run a selfhosted backend based on SQLite  from a single file. It supports Auth, Hooks, SSE, files and much more and enables users spinning up a backend in seconds. This library is a simple c driver to interact with the pocketbase backend and could easily be ported to a microcontroller.

Firebase_Logo

Backend API

Symmetric, Asysmetic, Block and Stream ciphers

cms icon

Pub Sub

Publish/Subscribe as a client to topics.

cms icon

SSE

Subscribe to database events/

cms icon

Auth

Login using Token

cms icon

File

Upload and download files.

cms icon

Admin

Admin operations.

Introduction

This lightweight library allows you to authenticate as a PocketBase client directly against your PocketBase backend. If a user record exists within your PocketBase Auth Collection, you can use those credentials to log that user in via C/C++ and subsequently perform authorized requests. The library provides a streamlined interface to CRUD (Create, Read, Update, Delete) records within your collections in real-time. It utilizes Radikant-Url-C to make https request and Radikant-Jwt-C to handle auth tokens.

Auth

FileEditViewProject
â–¶
â– 
Radikant — pb_auth_test.c
int main() {
// 1. Init
PB_Client_t *pb = pb_init("http://127.0.0.1:8090");
 
// 2. Login
printf("Logging in...\n");
if (pb_auth_login(pb, "users", "user@radikant.nl", "12341234") != PB_OK) {
printf("Login Failed.\n");
pb_free(pb);
return 1;
}
 
printf("Login Successful!\n");
pb_free(pb);
return 0;
}

Initially the user will log in with a username and a password beloging tot he Pocketbase user, the api requests a JWT id token from  Pocketbase  subequently return a response in json format containing; an id token and a refresh token. The id token can be used for TTL 1 hour to make requests and therefore is shortlived. The library doesnt automatically refresh tokens but checks upon ` request if the current token in possesion is still valid and if its expired use the refresh token to get a new id token and acces token. Therefore during a lengthy session the plain username and password is only sent once. It is possible to store the refresh token across reboots and continue a session but its comes with its own security considerations.

Admin

An admin is a “superuser” account which lives in a system auth collection. Super user have god-admin rights. Extra care is required from the user to use this superpower. It is very similair to normal user auth and is done by username password that is exchanged for an jwt token. The superuser had unrestricted acces and should really only be reserved for trusted api’s.

FileEditViewProject
â–¶
â– 
Radikant — pb_admin_ops.c
// Admin operations
pb_auth_admin_login(pb, ADMIN_EMAIL, ADMIN_PASS);
 
rjson_value *colls = pb_admin_get_collections(pb, 1);
 
if (colls) {
printf("Successfully retrieved collections data.\n");
rjson_print(colls, 1);
rjson_free(colls);
} else {
fprintf(stderr, "Failed to fetch collection list.\n");
}

File

Pocketbase API supports really easy file uploads and downloads. Also files can be uploaded to record, a clasic example is to set an avatar to a user. 

FileEditViewProject
â–¶
â– 
Radikant — pb_file_ops.c
// Upload and get file url
pb_error_t result = pb_upload_file(pb, COLLECTION, TEMP_FILE, FILE_FIELD);
 
if (result == PB_OK) {
char *url_str = pb_get_file_url(pb, COLLECTION, "RECORD_ID_123", TEMP_FILE);
printf("File available at: %s\n", url_str);
free(url_str); // Assuming the URL is heap allocated
} else {
fprintf(stderr, "Upload failed with error code: %d\n", result);
}

SSE

Pocktbase API natively supports Server sent events (SSE) (withouth hooks) which is very usefull if the user wants to listen to database changes and get notified by events. Applications can be IoT fleetmangement, chat, syncing a local state. 

FileEditViewProject
â–¶
â– 
Radikant — pb_stream_handler.c
// Listen to collection "Fields" in real-time
printf("Starting real-time stream for 'Fields'...\n");
 
pb_collection_stream(pb, "Fields", my_update_handler);
 
// The client remains active to process incoming event data
while(1) {
pb_loop(pb); // Keep the connection alive and handle callbacks
}

Pub Sub

Pocketbase supports pub sub events in a one to many model. In order to use this functionality you need to install a js hook in pocketbase pb_hooks folder. In the source there is a folder hooks with an example. 

File Edit View Project
â–¶
â– 
PocketClient — Realtime Broadcaster
// Publish to "world events" topic
pb_send_custom_request(pb, "POST", "/api/broadcast/world_events", payload) == PB_OK;
// Subscribe to "world events" topic
const char *subscriptions[] = { "world_events" };
pb_realtime_listen(pb, subscriptions, 1, on_message, NULL);

CRUD

Pocketbase supports pub sub events in a one to many model. 

FileEditView
â–¶ RecordManager.c
// Create and read record
rjson_value *response = pb_get_list(pb, "Fields");
pb_create_record(pb, "Fields", obj, &status, &body);
pb_read_record(pb, "Fields", "60t6s8z8m09tl3s", &status, &body);

Query

Pocketbase supports pub sub events in a one to many model. 

FileEditViewProject
â–¶
â– 
QueryTool — PocketBase Collection View
PB_Client_t *pb = pb_init(URL);
pb_auth_login(pb, "users", EMAIL, PASSWORD);
 
PB_Query_t q = {
.collection = COLLECTION,
.fields = "id,name,age,city,Salary,created,updated",
.filter = "",
.sort = "-created",
.page = 1,
.per_page = 50};
 
rjson_value *result = pb_query_execute(pb, &q);
 
if (result)
{
pb_table_t *table = pb_table_from_list(result);
if (table)
{
pb_print_table(table);
pb_free_table(table);
}
}
pb_free(pb);
return 0;
19:04:50 [SYS] Initializing client...
19:04:51 [AUTH] Logging in...

19:05:01 [DATA] Executing query on 'employees':
Salary  Age  ID               Name           Updated
------  ---  ---------------  -------------  ------------------------
80000   35   byvlq9uaozttzoc  Jan Oonk       2026-02-03 19:05:35.543Z
59000   28   pw29z7eqx42y533  Daan Willems   2026-02-03 11:59:23.942Z
43000   21   6p7aaw1y3tuplrt  Lara Hendriks  2026-02-03 11:59:48.170Z
36000   23   2pl7z7409wdgs7u  Finn Koster    2026-02-03 11:59:42.364Z
64000   32   q71874wrlo4zt0g  Eva Smit       2026-02-03 11:59:12.366Z