Skip to main content

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 ModeUse CaseCredential Requirements
Server-Side ModeNode.js server-side, SSRaccessKey
Browser Token ModeBrowser public data accessPre-generated token + timestamp
Browser Cookie ModeAuthenticated user private dataNo credentials needed (uses cookies)
SDK Automatic Handling

The official SDK automatically selects the appropriate authentication mode based on provided parameters, without manual specification.

Authentication Credentials

Required Credentials

Credential NameDescriptionHow to ObtainExample
App CodeUnique application identifierContact account managerapp-c2dd52a2
Access KeyAccess keyContact account managerak-xxxxxxxxxxxxx
Dataset CodeDataset identifierContact account manager0fefba76fe29...ff
Security Notice

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:

  1. SDK uses accessKey and current timestamp
  2. Generates token in real-time via HMAC-SHA256 algorithm
  3. Automatically adds authentication information to request headers:
    • X-App-Code: Application identifier
    • X-Dataset-Code: Dataset identifier
    • X-Time-Stamp: Current timestamp
    • X-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
Security Best Practices
  • ✅ Use environment variables to store Access Key
  • ✅ Add .env.local to .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.

Important Security Notice

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:

  1. SDK directly uses pre-generated token
  2. No real-time signature calculation
  3. Adds to request headers:
    • X-Token: Pre-generated token
    • X-Time-Stamp: Corresponding timestamp
    • X-App-Code and X-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>>;
}

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:

  1. SDK uses WebAPI mode
  2. Request automatically carries browser cookies
  3. Uses user's login state for authentication
  4. 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

FeatureServer-Side ModeToken ModeCookie Mode
Runtime EnvironmentNode.js server-sideBrowserBrowser
Authentication InfoaccessKeytoken + timestampCookie
Token GenerationReal-timePre-generatedNo token needed
Validity PeriodUnlimited10 minutesDepends on login state
SecurityHighestHighMedium
Use CasesSSR, API routesPublic data accessPrivate data access

Error Handling

Error CodeDescriptionSolution
1002Signature verification failedCheck if Access Key is correct
1003Timestamp expiredToken expired, regenerate
1004Application does not existCheck if App Code is correct
1005Dataset does not existCheck if Dataset Code is correct
1006No access permissionConfirm 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

Key Security Rules
  • 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)

For Reference Only

SDK automatically handles signature generation, usually no need to worry about underlying implementation.

Signature generation steps:

  1. Collect parameters:

    {
    accessKey: "your-access-key",
    timeStamp: "1758903130713",
    appCode: "app-c2dd52a2",
    datasetCode: "0fefba76fe29..."
    }
  2. Sort by dictionary order and concatenate:

    accessKey=your-access-key&appCode=app-c2dd52a2&datasetCode=0fefba76fe29...&timeStamp=1758903130713
  3. Calculate signature using HMAC-SHA256:

    const token = crypto
    .createHmac("sha256", secretKey)
    .update(sortedParams, "utf8")
    .digest("base64");
  4. Add to request header:

    X-Token: jdqqGtzecF2I6FIW0s2xv0YRIprUqt0FLEJPYCgGB+4=

Frequently Asked Questions

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:

  1. Generate token on server-side
  2. Return to frontend via API
  3. Frontend uses pre-generated token

Q: What if Access Key is leaked?

A: Take immediate action:

  1. Contact account manager to replace with new Access Key
  2. Disable old Access Key
  3. Update all applications using the old key
  4. 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

Need Help?

If you encounter authentication-related issues:

  1. Check the error handling section in this document
  2. Check GitHub Issues
  3. Contact account manager for technical support