Authentication Guide
This document provides an in-depth introduction to Lovrabet OpenAPI's authentication mechanisms, token management, and best practices.
Authentication Overview
Lovrabet OpenAPI uses HMAC-SHA256 signature-based authentication. Based on runtime environment and usage scenarios, it supports three authentication modes:
| Authentication Mode | Use Case | Credential Requirements |
|---|---|---|
| Server-Side Mode | Node.js server-side, SSR | accessKey |
| Browser Token Mode | Browser public data access | Pre-generated token + timestamp |
| Browser Cookie Mode | Authenticated user private data | No credentials needed (uses cookies) |
The official SDK automatically selects the appropriate authentication mode based on provided parameters, without manual specification.
Authentication Credentials
Required Credentials
| Credential Name | Description | How to Obtain | Example |
|---|---|---|---|
| App Code | Unique application identifier | Contact account manager | app-c2dd52a2 |
| Access Key | Access key | Contact account manager | ak-xxxxxxxxxxxxx |
| Dataset Code | Dataset identifier | Contact account manager | 0fefba76fe29...ff |
Access Key is sensitive information. Please keep it secure and do not leak or hardcode it in code.
Mode 1: Server-Side Authentication (accessKey)
Suitable for Node.js server-side, Next.js SSR, API routes, and similar scenarios.
Basic Usage
import { createClient } from "@lovrabet/sdk";
const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY, // ✅ Read from environment variable
models: {
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
},
});
// SDK automatically generates token and handles authentication
const users = await client.models.users.filter();
How It Works
When accessKey is provided:
- SDK uses
accessKeyand current timestamp - Generates token in real-time via HMAC-SHA256 algorithm
- Automatically adds authentication information to request headers:
X-App-Code: Application identifierX-Dataset-Code: Dataset identifierX-Time-Stamp: Current timestampX-Token: Generated signature
Next.js Server Component Example
// app/users/page.tsx (Server Component)
import { createClient } from "@lovrabet/sdk";
// Create client in server component
const client = createClient({
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
models: {
users: {
tableName: "users",
datasetCode: process.env.LOVRABET_DATASET_CODE!,
},
},
});
export default async function UsersPage() {
// Call directly on server-side
const { tableData: users } = await client.models.users.filter();
return (
<div>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Environment Variable Configuration
Create .env.local file:
LOVRABET_APP_CODE=your-app-code
LOVRABET_ACCESS_KEY=your-access-key
LOVRABET_DATASET_CODE=your-dataset-code
- ✅ Use environment variables to store Access Key
- ✅ Add
.env.localto.gitignore - ✅ Use different keys for different environments
- ❌ Never hardcode keys in code
Mode 2: Browser Token Authentication (Pre-generated)
Suitable for browser-side public data access, unauthenticated users, and similar scenarios.
Never use accessKey in browser code! Token must be generated on server-side and then passed to browser.
Step 1: Server-Side Token Generation
Use the generateOpenApiToken() function to generate tokens:
// app/api/token/route.ts
import { generateOpenApiToken } from "@lovrabet/sdk";
import { NextResponse } from "next/server";
export async function GET() {
try {
const result = await generateOpenApiToken({
appCode: process.env.LOVRABET_APP_CODE!,
datasetCode: process.env.LOVRABET_DATASET_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
// secretKey: "lovrabet", // Optional, defaults to "lovrabet"
// timestamp: Date.now(), // Optional, defaults to current time
});
// result contains: { token, timestamp, expiresAt }
return NextResponse.json(result);
} catch (error) {
return NextResponse.json({ error: "Token generation failed" }, { status: 500 });
}
}
Response Data Structure:
{
token: string; // Generated token
timestamp: number; // Timestamp (milliseconds)
expiresAt: Date; // Expiration time
}
Step 2: Browser Token Usage
// app/users/client-page.tsx
"use client";
import { createClient } from "@lovrabet/sdk";
import { useEffect, useState } from "react";
export default function ClientUsersPage() {
const [users, setUsers] = useState([]);
useEffect(() => {
async function init() {
// 1. Get token from server
const { token, timestamp } = await fetch("/api/token").then((r) =>
r.json()
);
// 2. Create client (using token and timestamp)
const client = createClient({
appCode: "your-app-code",
token: token, // Pre-generated token
timestamp: timestamp, // Corresponding timestamp
models: {
users: { tableName: "users", datasetCode: "your-dataset-code" },
},
});
// 3. Query data
const { tableData } = await client.models.users.filter();
setUsers(tableData);
}
init();
}, []);
return (
<div>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
How It Works
When token and timestamp are provided:
- SDK directly uses pre-generated token
- No real-time signature calculation
- Adds to request headers:
X-Token: Pre-generated tokenX-Time-Stamp: Corresponding timestampX-App-CodeandX-Dataset-Code
Token Lifecycle Management
Token validity period is 10 minutes (600 seconds), and needs to be refreshed after expiration.
Check if Token is About to Expire
import { isTokenExpiring, getTokenRemainingTime } from "@lovrabet/sdk";
const timestamp = Date.now();
// Check if about to expire (default buffer time 1 minute)
if (isTokenExpiring(timestamp)) {
console.log("Token about to expire, needs refresh");
}
// Check if about to expire (custom buffer time 2 minutes)
if (isTokenExpiring(timestamp, 120000)) {
console.log("Will expire within 2 minutes");
}
// Get remaining time (milliseconds)
const remaining = getTokenRemainingTime(timestamp);
console.log(`Token has ${remaining / 1000} seconds remaining`);
Automatic Token Refresh
"use client";
import {
createClient,
isTokenExpiring,
getTokenRemainingTime,
} from "@lovrabet/sdk";
import { useEffect, useState } from "react";
export default function UsersWithAutoRefresh() {
const [client, setClient] = useState(null);
const [timestamp, setTimestamp] = useState(null);
const [remainingTime, setRemainingTime] = useState(null);
// Initialize
useEffect(() => {
fetchTokenAndCreateClient();
}, []);
// Periodically check token validity
useEffect(() => {
if (!timestamp) return;
const interval = setInterval(() => {
const remaining = getTokenRemainingTime(timestamp);
setRemainingTime(remaining);
// Refresh 1 minute early
if (isTokenExpiring(timestamp, 60000)) {
console.log("Token about to expire, refreshing...");
fetchTokenAndCreateClient();
}
}, 10000); // Check every 10 seconds
return () => clearInterval(interval);
}, [timestamp]);
async function fetchTokenAndCreateClient() {
const { token, timestamp: newTimestamp } = await fetch("/api/token").then(
(r) => r.json()
);
const newClient = createClient({
appCode: "your-app-code",
token: token,
timestamp: newTimestamp,
models: {
users: { tableName: "users", datasetCode: "your-dataset-code" },
},
});
setClient(newClient);
setTimestamp(newTimestamp);
}
// Display remaining time
return (
<div>
<p>Token remaining: {Math.floor((remainingTime || 0) / 1000)} seconds</p>
{/* ... other content */}
</div>
);
}
Batch Token Generation
If you need to generate tokens for multiple datasets, use the TokenGenerator class:
import { TokenGenerator } from "@lovrabet/sdk";
const generator = new TokenGenerator(
process.env.LOVRABET_ACCESS_KEY!,
"lovrabet" // secretKey, optional
);
// Batch generate
const tokens = await generator.generateBatch({
appCode: "your-app-code",
datasets: [
{ name: "users", code: "dataset-001" },
{ name: "orders", code: "dataset-002" },
{ name: "products", code: "dataset-003" },
],
// timestamp: Date.now(), // Optional, defaults to current time
});
// Use generated tokens
console.log(tokens.users.token);
console.log(tokens.users.timestamp);
console.log(tokens.users.expiresAt);
console.log(tokens.orders.token);
console.log(tokens.products.token);
// Return an API endpoint
export async function GET() {
return NextResponse.json(tokens);
}
TokenGenerator Methods
class TokenGenerator {
constructor(accessKey: string, secretKey?: string);
// Generate single token
generate(params: {
appCode: string;
datasetCode: string;
timestamp?: number;
}): Promise<TokenResult>;
// Batch generate tokens
generateBatch(params: {
appCode: string;
datasets: Array<{ name: string; code: string }>;
timestamp?: number;
}): Promise<Record<string, TokenResult>>;
}
Mode 3: Browser Cookie Authentication
Suitable for authenticated users accessing private data.
Usage
"use client";
import { createClient } from "@lovrabet/sdk";
// No authentication information needed
const client = createClient({
appCode: "your-app-code",
models: {
orders: { tableName: "orders", datasetCode: "your-dataset-code" },
},
});
// Request automatically carries browser's login cookie
const { tableData } = await client.models.orders.filter();
How It Works
When neither accessKey nor token is provided:
- SDK uses WebAPI mode
- Request automatically carries browser cookies
- Uses user's login state for authentication
- Suitable for authenticated users accessing their own data
Use Cases
- ✅ User order list
- ✅ Personal profile data
- ✅ User favorites/shopping cart
- ❌ Public data access (unauthenticated users)
Authentication Mode Selection
Decision Tree
Is it server-side?
├─ Yes → Use accessKey mode (Mode 1)
└─ No (browser-side)
├─ User authenticated and accessing private data?
│ ├─ Yes → Use cookie mode (Mode 3)
│ └─ No → Use pre-generated token mode (Mode 2)
└─ Public data access?
└─ Yes → Use pre-generated token mode (Mode 2)
Comparison Table
| Feature | Server-Side Mode | Token Mode | Cookie Mode |
|---|---|---|---|
| Runtime Environment | Node.js server-side | Browser | Browser |
| Authentication Info | accessKey | token + timestamp | Cookie |
| Token Generation | Real-time | Pre-generated | No token needed |
| Validity Period | Unlimited | 10 minutes | Depends on login state |
| Security | Highest | High | Medium |
| Use Cases | SSR, API routes | Public data access | Private data access |
Error Handling
Authentication-Related Error Codes
| Error Code | Description | Solution |
|---|---|---|
| 1002 | Signature verification failed | Check if Access Key is correct |
| 1003 | Timestamp expired | Token expired, regenerate |
| 1004 | Application does not exist | Check if App Code is correct |
| 1005 | Dataset does not exist | Check if Dataset Code is correct |
| 1006 | No access permission | Confirm application has dataset access |
Error Handling Example
import { LovrabetError } from "@lovrabet/sdk";
try {
const users = await client.models.users.filter();
} catch (error) {
if (error instanceof LovrabetError) {
switch (error.statusCode) {
case 1002:
console.error("Signature verification failed, check Access Key");
break;
case 1003:
console.error("Token expired, refreshing...");
// Re-fetch token
await fetchTokenAndCreateClient();
break;
case 1006:
console.error("No permission to access this dataset");
break;
default:
console.error("API error:", error.message);
}
} else {
console.error("Unknown error:", error);
}
}
Best Practices
1. Credential Security
- ✅ Server-side: Use environment variables to store Access Key
- ✅ Browser: Use pre-generated token, never expose Access Key
- ✅ Regularly rotate Access Key
- ✅ Use different keys for different environments
- ❌ Never hardcode Access Key in client-side code
- ❌ Never commit Access Key to code repository
Wrong Example:
// ❌ Dangerous! Will expose Access Key
const client = createClient({
accessKey: "ak-xxxxx", // Never do this!
});
Correct Example:
// ✅ Server-side: Use environment variables
const client = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
});
// ✅ Browser: Use pre-generated token
const { token } = await fetch("/api/token").then((r) => r.json());
const client = createClient({ token });
2. Client Instance Reuse
// ✅ Recommended: Reuse client instance
const client = createClient({
/* config */
});
const users = await client.models.users.filter();
const orders = await client.models.orders.filter();
// ❌ Avoid: Repeatedly creating clients
const client1 = createClient({
/* config */
});
const users = await client1.models.users.filter();
const client2 = createClient({
/* config */
}); // Unnecessary
const orders = await client2.models.orders.filter();
3. Token Refresh Strategy
// Refresh early, avoid expiration
if (isTokenExpiring(timestamp, 60000)) {
// Refresh 1 minute early
await refreshToken();
}
// Retry on error
try {
await api.call();
} catch (error) {
if (error.statusCode === 1003) {
// Token expired, refresh and retry
await refreshToken();
await api.call();
}
}
Advanced Usage
Dynamic Token Update
const client = createClient({
appCode: "your-app-code",
models: {
/* ... */
},
});
// Update token later
client.setToken(newToken, newTimestamp);
Custom Request Options
const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY,
models: {
/* ... */
},
options: {
timeout: 30000, // 30 second timeout
// Other fetch options
},
});
Signature Algorithm Details (Advanced)
SDK automatically handles signature generation, usually no need to worry about underlying implementation.
Signature generation steps:
-
Collect parameters:
{
accessKey: "your-access-key",
timeStamp: "1758903130713",
appCode: "app-c2dd52a2",
datasetCode: "0fefba76fe29..."
} -
Sort by dictionary order and concatenate:
accessKey=your-access-key&appCode=app-c2dd52a2&datasetCode=0fefba76fe29...&timeStamp=1758903130713 -
Calculate signature using HMAC-SHA256:
const token = crypto
.createHmac("sha256", secretKey)
.update(sortedParams, "utf8")
.digest("base64"); -
Add to request header:
X-Token: jdqqGtzecF2I6FIW0s2xv0YRIprUqt0FLEJPYCgGB+4=
Frequently Asked Questions
Q: Why is SDK recommended?
A: SDK encapsulates all authentication details, including:
- ✅ Automatic signature generation
- ✅ Timestamp handling
- ✅ Token lifecycle management
- ✅ Error handling and retry
- ✅ TypeScript type support
Q: How long is the token valid?
A: Token validity period is 10 minutes (600 seconds). Recommend refreshing 1-2 minutes early to avoid expiration.
Q: How to use securely in browser?
A: Never use accessKey in browser, instead:
- Generate token on server-side
- Return to frontend via API
- Frontend uses pre-generated token
Q: What if Access Key is leaked?
A: Take immediate action:
- Contact account manager to replace with new Access Key
- Disable old Access Key
- Update all applications using the old key
- Audit potentially affected data
Q: Can token validity period be customized?
A: No, token validity period is fixed at 10 minutes. This is by security design.
Next Steps
- API Reference - View complete endpoint documentation
- Quick Start - Get hands-on quickly with examples
Need Help?
If you encounter authentication-related issues:
- Check the error handling section in this document
- Check GitHub Issues
- Contact account manager for technical support