Authentication - C SDK Documentation
Overview
Authentication in BosBase is stateless and token-based. A client is considered authenticated as long as it sends a valid Authorization: YOUR_AUTH_TOKEN header with requests.
Key Points:
- No sessions: BosBase APIs are fully stateless (tokens are not stored in the database)
- No logout endpoint: To “logout”, simply clear the token from your local state (
bosbase_auth_clear()) - Token generation: Auth tokens are generated through auth collection Web APIs or programmatically
- Admin users:
_superuserscollection works like regular auth collections but with full access (API rules are ignored) - OAuth2 limitation: OAuth2 is not supported for
_superuserscollection
Authentication Methods
BosBase supports multiple authentication methods that can be configured individually for each auth collection:
- Password Authentication - Email/username + password
- OTP Authentication - One-time password via email
- OAuth2 Authentication - Google, GitHub, Microsoft, etc.
- Multi-factor Authentication (MFA) - Requires 2 different auth methods
Authentication Store
The SDK maintains an authentication store that automatically manages the authentication state:
#include "bosbase_c.h"
#include <stdio.h>
int main() {
bosbase_client* pb = bosbase_client_new("http://localhost:8090", "en-US");
// Check authentication status
const char* token = bosbase_auth_token(pb);
if (token) {
printf("Current token: %s\n", token);
}
char* record_json = bosbase_auth_record(pb);
if (record_json) {
printf("Authenticated user: %s\n", record_json);
bosbase_free_string(record_json);
}
// Clear authentication (logout)
bosbase_auth_clear(pb);
bosbase_client_free(pb);
return 0;
}
Password Authentication
Authenticate using email/username and password. The identity field can be configured in the collection options (default is email).
Backend Endpoint: POST /api/collections/{collection}/auth-with-password
Basic Usage
#include "bosbase_c.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
bosbase_client* pb = bosbase_client_new("http://localhost:8090", "en-US");
// Authenticate with email and password
char* auth_json = NULL;
bosbase_error* err = NULL;
if (bosbase_collection_auth_with_password(pb, "users",
"test@example.com", "password123", "{}", NULL, NULL,
"{}", "{}", &auth_json, &err) == 0) {
printf("Authentication successful: %s\n", auth_json);
// Token is automatically stored
const char* token = bosbase_auth_token(pb);
printf("Token: %s\n", token);
bosbase_free_string(auth_json);
} else {
fprintf(stderr, "Authentication failed: %s\n", err->message);
bosbase_free_error(err);
}
bosbase_client_free(pb);
return 0;
}
Response Format
The authentication response is a JSON object:
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"record": {
"id": "record_id",
"email": "test@example.com",
...
}
}
Error Handling with MFA
char* auth_json = NULL;
bosbase_error* err = NULL;
if (bosbase_collection_auth_with_password(pb, "users",
"test@example.com", "pass123", "{}", NULL, NULL,
"{}", "{}", &auth_json, &err) != 0) {
if (err && err->status == 401) {
// Check for MFA requirement (parse err->response JSON)
// Handle MFA flow (see Multi-factor Authentication section)
printf("MFA required\n");
} else {
fprintf(stderr, "Authentication failed: %s\n", err->message);
}
bosbase_free_error(err);
} else {
bosbase_free_string(auth_json);
}
OTP Authentication
One-time password authentication via email.
Backend Endpoints:
POST /api/collections/{collection}/request-otp- Request OTPPOST /api/collections/{collection}/auth-with-otp- Authenticate with OTP
Request OTP
// Send OTP to user's email
const char* otp_body = "{\"email\":\"test@example.com\"}";
char* otp_result = NULL;
bosbase_error* err = NULL;
if (bosbase_send(pb, "/api/collections/users/request-otp", "POST",
otp_body, "{}", "{}", 30000, NULL, 0, &otp_result, &err) == 0) {
// Parse otp_result JSON to get otpId
printf("OTP requested: %s\n", otp_result);
bosbase_free_string(otp_result);
} else {
fprintf(stderr, "OTP request failed: %s\n", err->message);
bosbase_free_error(err);
}
Authenticate with OTP
// Step 1: Request OTP (see above)
// Step 2: User enters OTP from email
const char* auth_otp_body =
"{\"otpId\":\"OTP_ID_FROM_STEP_1\",\"otp\":\"123456\"}";
char* auth_json = NULL;
if (bosbase_send(pb, "/api/collections/users/auth-with-otp", "POST",
auth_otp_body, "{}", "{}", 30000, NULL, 0, &auth_json, &err) == 0) {
printf("OTP authentication successful: %s\n", auth_json);
bosbase_free_string(auth_json);
} else {
fprintf(stderr, "OTP authentication failed: %s\n", err->message);
bosbase_free_error(err);
}
OAuth2 Authentication
Backend Endpoint: POST /api/collections/{collection}/auth-with-oauth2
Manual Code Exchange
// Get auth methods first
char* methods_json = NULL;
if (bosbase_send(pb, "/api/collections/users/auth-methods", "GET",
NULL, "{}", "{}", 30000, NULL, 0, &methods_json, NULL) == 0) {
// Parse methods_json to find OAuth2 provider
// Extract provider name, codeVerifier, etc.
bosbase_free_string(methods_json);
}
// Exchange code for token (after OAuth2 redirect)
const char* oauth2_body =
"{\"provider\":\"google\","
"\"code\":\"AUTHORIZATION_CODE\","
"\"codeVerifier\":\"CODE_VERIFIER\","
"\"redirectUrl\":\"https://yourapp.com/callback\"}";
char* oauth2_json = NULL;
if (bosbase_send(pb, "/api/collections/users/auth-with-oauth2", "POST",
oauth2_body, "{}", "{}", 30000, NULL, 0, &oauth2_json, &err) == 0) {
printf("OAuth2 authentication successful: %s\n", oauth2_json);
bosbase_free_string(oauth2_json);
} else {
fprintf(stderr, "OAuth2 failed: %s\n", err->message);
bosbase_free_error(err);
}
Multi-Factor Authentication (MFA)
Requires 2 different auth methods.
char* auth_json = NULL;
bosbase_error* err = NULL;
// First auth method (password)
if (bosbase_collection_auth_with_password(pb, "users",
"test@example.com", "pass123", "{}", NULL, NULL,
"{}", "{}", &auth_json, &err) != 0) {
if (err && err->status == 401) {
// Parse err->response to check for mfaId
// If mfaId present, proceed with second factor
// Second auth method (OTP)
const char* otp_body = "{\"email\":\"test@example.com\"}";
char* otp_result = NULL;
if (bosbase_send(pb, "/api/collections/users/request-otp", "POST",
otp_body, "{}", "{}", 30000, NULL, 0, &otp_result, NULL) == 0) {
// Parse otp_result to get otpId
// Then authenticate with OTP and mfaId
const char* mfa_otp_body =
"{\"otpId\":\"OTP_ID\",\"otp\":\"123456\","
"\"mfaId\":\"MFA_ID_FROM_FIRST_AUTH\"}";
char* mfa_auth_json = NULL;
bosbase_send(pb, "/api/collections/users/auth-with-otp", "POST",
mfa_otp_body, "{}", "{}", 30000, NULL, 0,
&mfa_auth_json, NULL);
bosbase_free_string(mfa_auth_json);
}
bosbase_free_string(otp_result);
}
bosbase_free_error(err);
} else {
bosbase_free_string(auth_json);
}
Auth Token Verification
Verify token by calling authRefresh().
Backend Endpoint: POST /api/collections/{collection}/auth-refresh
char* refresh_json = NULL;
bosbase_error* err = NULL;
if (bosbase_collection_auth_refresh(pb, "users", "{}", NULL, NULL,
"{}", "{}", &refresh_json, &err) == 0) {
printf("Token is valid: %s\n", refresh_json);
bosbase_free_string(refresh_json);
} else {
fprintf(stderr, "Token verification failed: %s\n", err->message);
bosbase_auth_clear(pb); // Clear invalid token
bosbase_free_error(err);
}
List Available Auth Methods
Backend Endpoint: GET /api/collections/{collection}/auth-methods
char* methods_json = NULL;
if (bosbase_send(pb, "/api/collections/users/auth-methods", "GET",
NULL, "{}", "{}", 30000, NULL, 0, &methods_json, NULL) == 0) {
// Parse JSON to check:
// - methods.password.enabled
// - methods.oauth2.providers
// - methods.mfa.enabled
printf("Auth methods: %s\n", methods_json);
bosbase_free_string(methods_json);
}
Password Reset
// Request password reset email
const char* reset_request = "{\"email\":\"user@example.com\"}";
bosbase_error* err = NULL;
if (bosbase_collection_request_password_reset(pb, "users",
"user@example.com", "{}", "{}", "{}", &err) != 0) {
fprintf(stderr, "Reset request failed: %s\n", err->message);
bosbase_free_error(err);
}
// Confirm password reset (on reset page)
if (bosbase_collection_confirm_password_reset(pb, "users",
"RESET_TOKEN", "newpassword123", "newpassword123",
"{}", "{}", &err) != 0) {
fprintf(stderr, "Reset confirmation failed: %s\n", err->message);
bosbase_free_error(err);
}
Email Verification
// Request verification email
if (bosbase_collection_request_verification(pb, "users",
"user@example.com", "{}", "{}", "{}", &err) != 0) {
fprintf(stderr, "Verification request failed: %s\n", err->message);
bosbase_free_error(err);
}
// Confirm verification (on verification page)
if (bosbase_collection_confirm_verification(pb, "users",
"VERIFICATION_TOKEN", "{}", "{}", "{}", &err) != 0) {
fprintf(stderr, "Verification failed: %s\n", err->message);
bosbase_free_error(err);
}
Saving and Loading Auth Tokens
// Save auth token and record
const char* token = "eyJhbGciOiJIUzI1NiJ9...";
const char* record_json = "{\"id\":\"user_id\",\"email\":\"user@example.com\"}";
if (bosbase_auth_save(pb, token, record_json, &err) == 0) {
printf("Auth saved successfully\n");
} else {
fprintf(stderr, "Failed to save auth: %s\n", err->message);
bosbase_free_error(err);
}
// Later, retrieve saved auth
const char* saved_token = bosbase_auth_token(pb);
char* saved_record = bosbase_auth_record(pb);
if (saved_token && saved_record) {
printf("Restored auth: %s\n", saved_record);
bosbase_free_string(saved_record);
}
Complete Example
#include "bosbase_c.h"
#include <stdio.h>
#include <stdlib.h>
int authenticate_user(bosbase_client* pb, const char* email, const char* password) {
char* auth_json = NULL;
bosbase_error* err = NULL;
// Try password authentication
if (bosbase_collection_auth_with_password(pb, "users", email, password,
"{}", NULL, NULL, "{}", "{}", &auth_json, &err) == 0) {
printf("Successfully authenticated: %s\n", email);
bosbase_free_string(auth_json);
return 0;
}
// Check for MFA requirement
if (err && err->status == 401) {
// Parse err->response to check for mfaId
// Handle MFA flow...
printf("MFA required\n");
} else {
fprintf(stderr, "Authentication failed: %s\n", err->message);
}
bosbase_free_error(err);
return 1;
}
int main() {
bosbase_client* pb = bosbase_client_new("http://localhost:8090", "en-US");
if (authenticate_user(pb, "user@example.com", "password123") == 0) {
// User is authenticated, make authenticated requests
const char* token = bosbase_auth_token(pb);
printf("Using token: %s\n", token);
}
bosbase_client_free(pb);
return 0;
}
Best Practices
- Secure Token Storage: Never expose tokens in logs or error messages
- Token Refresh: Implement automatic token refresh before expiration
- Error Handling: Always handle MFA requirements and token expiration
- OAuth2 Security: Always validate the
stateparameter in OAuth2 callbacks - Memory Management: Always free strings returned by SDK functions
- Error Cleanup: Always free error objects after handling