API keys provide a secure way to authenticate server-to-server requests without requiring a user session. This guide explains how to use API keys with the SnackBase JavaScript SDK.
What are API Keys?
API keys are long-lived credentials that allow your server to authenticate with SnackBase without requiring a user login flow. They’re ideal for:
- Backend services and cron jobs
- Webhook endpoints
- Server-side data processing
- Automated scripts
API keys should only be used on the server side. Never expose API keys in
client-side code or public repositories.
Setting Up API Keys
Generate an API Key
- Log in to your SnackBase admin panel
- Navigate to API Keys
- Click + New API Key
- Enter a description (e.g., “Production API”)
- Copy the generated key
API keys are only shown once at creation. Store them securely in your
environment variables.
Using API Keys
Basic Usage
import { SnackBaseClient } from "@snackbase/sdk";
const client = new SnackBaseClient({
baseUrl: "https://api.example.com",
apiKey: process.env.SNACKBASE_API_KEY,
});
// All requests will now use the API key
const posts = await client.records.list("posts");
Environment Variables
Store your API key in environment variables:
# .env
SNACKBASE_API_KEY=sbak_live_xxxxxxxxxxxxx
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
Different Keys for Different Environments
Use different API keys for different environments:
# .env.development
SNACKBASE_API_KEY=sbak_test_xxxxxxxxxxxxx
SNACKBASE_URL=http://localhost:8000
# .env.production
SNACKBASE_API_KEY=sbak_live_xxxxxxxxxxxxx
SNACKBASE_URL=https://api.example.com
API Key vs User Authentication
| Feature | API Key | User Authentication |
|---|
| Use Case | Server-to-server | End-user requests |
| Token Type | Long-lived | Short-lived (15 minutes) |
| Permissions | Full account access | Role-based |
| Rate Limits | Higher limits | Standard limits |
| Location | Server only | Client + Server |
| User Context | None (service account) | Specific user |
Server-Side Operations
Express.js Example
import express from "express";
import { SnackBaseClient } from "@snackbase/sdk";
const app = express();
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
app.get("/posts", async (req, res) => {
try {
const posts = await client.records.list("posts", {
filter: { status: "published" },
limit: 10,
});
res.json(posts);
} catch (error) {
res.status(500).json({ error: "Failed to fetch posts" });
}
});
app.post("/posts", async (req, res) => {
try {
const post = await client.records.create("posts", req.body);
res.json(post);
} catch (error) {
res.status(500).json({ error: "Failed to create post" });
}
});
app.listen(3000);
Next.js Example
// app/posts/page.tsx
import { SnackBaseClient } from "@snackbase/sdk";
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
export default async function PostsPage() {
const posts = await client.records.list("posts", {
filter: { status: "published" },
});
return (
<div>
<h1>Posts</h1>
<ul>
{posts.items.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
Background Jobs
import { SnackBaseClient } from "@snackbase/sdk";
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
// Run daily cleanup job
async function cleanupOldRecords() {
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const oldRecords = await client.records.list("logs", {
filter: { createdAt: `< ${thirtyDaysAgo.toISOString()}` },
});
for (const record of oldRecords.items) {
await client.records.delete("logs", record.id);
}
console.log(`Deleted ${oldRecords.total} old records`);
}
// Run with a scheduler like node-cron
Webhook Handling
import { SnackBaseClient } from "@snackbase/sdk";
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
app.post("/webhooks/payment", async (req, res) => {
const { event, data } = req.body;
switch (event) {
case "payment.succeeded":
// Update order in SnackBase
await client.records.update("orders", data.orderId, {
status: "paid",
paidAt: new Date().toISOString(),
});
break;
case "payment.failed":
await client.records.update("orders", data.orderId, {
status: "payment_failed",
});
break;
}
res.sendStatus(200);
});
Admin Operations
API keys have full access to account operations:
// Create a new user
const user = await client.users.create({
email: "[email protected]",
password: "SecurePassword123!",
accountRole: "member",
});
// Assign a role
await client.roles.addUserToRole("roleId", "userId");
// Update collection rules
await client.collectionRules.update("collectionId", {
rules: [
{
name: "read-only",
permissions: ["read"],
expression: "user.role == 'viewer'",
},
],
});
Error Handling
import {
AuthenticationError,
AuthorizationError,
NetworkError,
} from "@snackbase/sdk";
try {
const posts = await client.records.list("posts");
} catch (error) {
if (error instanceof AuthenticationError) {
console.error("Invalid API key");
} else if (error instanceof AuthorizationError) {
console.error("API key lacks required permissions");
} else if (error instanceof NetworkError) {
console.error("Network error");
} else {
console.error("Unknown error:", error);
}
}
Security Best Practices
1. Environment Variables
Never hardcode API keys:
// Bad
const client = new SnackBaseClient({
baseUrl: "https://api.example.com",
apiKey: "sbak_live_xxxxxxxxxxxxx",
});
// Good
const client = new SnackBaseClient({
baseUrl: process.env.SNACKBASE_URL!,
apiKey: process.env.SNACKBASE_API_KEY!,
});
2. Use Different Keys for Different Services
Create separate API keys for different services:
# .env
SNACKBASE_API_KEY_WEB=sbak_live_web_xxxxxxxxxxxxx
SNACKBASE_API_KEY_CRON=sbak_live_cron_xxxxxxxxxxxxx
SNACKBASE_API_KEY_WEBHOOKS=sbak_live_hooks_xxxxxxxxxxxxx
3. Rotate API Keys Regularly
Periodically rotate your API keys:
- Create a new API key
- Update your environment variables
- Deploy the changes
- Delete the old API key
4. Use Key Prefixes
API keys include prefixes to identify their type:
sbak_live_ - Production keys
sbak_test_ - Test/development keys
Verify the key type in production:
const apiKey = process.env.SNACKBASE_API_KEY!;
if (!apiKey.startsWith("sbak_live_")) {
throw new Error("Production API key required");
}
5. Monitor Usage
Monitor your API key usage in the SnackBase admin panel to detect unauthorized access.
Rate Limits
API keys have higher rate limits than user authentication:
| Authentication | Rate Limit |
|---|
| User Token | 100 requests/minute |
| API Key | 1000 requests/minute |
Actual rate limits depend on your SnackBase plan. Contact support for
custom limits.
Testing
Use test API keys during development:
// Test environment
const client = new SnackBaseClient({
baseUrl: "https://test-api.example.com",
apiKey: process.env.SNACKBASE_TEST_API_KEY!,
});
Next Steps