Authentication
The Lovrabet SDK supports several authentication methods to cover the security needs of different scenarios. This guide walks through configuring and using each one.
💡 Prerequisite Before you start, make sure the SDK is configured. Letting the CLI generate the configuration automatically is recommended.
Authentication methods at a glance
The SDK supports the following authentication methods:
- User token authentication - for scenarios where the user is already logged in
- OpenAPI key authentication - for server-to-server calls
- Cookie authentication (automatic) - for browser environments with a logged-in user
- Runtime switching - update credentials dynamically
👤 User token authentication
Option 1: specify via ClientConfig (recommended)
import { registerModels, createClient } from "@lovrabet/sdk";
// 先注册基础配置(推荐使用 CLI 自动生成)
registerModels({
appCode: "my-app",
models: [
{ datasetCode: "8d2dcbae08b54bdd84c00be558ed48df", tableName: "users", alias: "users" },
{ datasetCode: "a1b2c3d4e5f6789012345678abcdef12", tableName: "orders", alias: "orders" },
],
});
// 创建带认证的客户端
const client = createClient({
token: "your-user-token",
});
// 标准方式访问
const users = await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();
// 或使用别名(语法糖)
const users = await client.models.users.filter();Option 2: pass the configuration directly
const client = createClient({
appCode: "my-app",
token: "your-user-token",
models: [
{ datasetCode: "8d2dcbae08b54bdd84c00be558ed48df", tableName: "users", alias: "users" },
{ datasetCode: "a1b2c3d4e5f6789012345678abcdef12", tableName: "orders", alias: "orders" },
],
});
// 标准方式访问
const users = await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();Practical example
// auth/client.ts
import { createClient } from "@lovrabet/sdk";
import "./api/api"; // 导入 CLI 生成的配置
import { getAuthToken } from "./auth-service";
// 创建认证客户端工厂
export const createAuthenticatedClient = () => {
const token = getAuthToken(); // 从存储中获取 token
return createClient({
token,
options: {
onError: (error) => {
if (error.message.includes("unauthorized")) {
// Token 失效,重定向到登录页
window.location.href = "/login";
}
},
},
});
};
// 使用
const client = createAuthenticatedClient();
// 标准方式访问
const users = await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();
// 或使用别名
const users = await client.models.users.filter();🔑 OpenAPI key authentication
OpenAPI key authentication is designed for server-to-server calls and provides stronger security.
🚨 Security warning: do not use accessKey in the browser
⚠️ accessKey must only be used on the server!
Using accessKey in a browser environment poses serious security risks:
The correct approach:
Authentication flow comparison:
Secure server-side proxy pattern
The recommended pattern is to create an API proxy on the server that gives the frontend secure access to data:
// 服务器端:使用 accessKey
import { createClient } from '@lovrabet/sdk';
const serverClient = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
});
// API 路由:/api/users
export async function GET(request: Request) {
// 验证用户身份(从 session/cookie)
const user = await validateUser(request);
if (!user) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// 使用服务器端 client 获取数据
const users = await serverClient.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();
return Response.json(users);
}
// 浏览器端:调用服务器 API
fetch('/api/users')
.then(res => res.json())
.then(data => console.log(data));Option 1: specify via ClientConfig (recommended)
// 先注册基础配置(推荐使用 CLI 自动生成)
registerModels({
appCode: "my-app",
models: [
{ datasetCode: "8d2dcbae08b54bdd84c00be558ed48df", tableName: "users", alias: "users" },
{ datasetCode: "a1b2c3d4e5f6789012345678abcdef12", tableName: "analytics", alias: "analytics" },
],
});
// 创建带密钥认证的客户端
const client = createClient({
accessKey: "your-access-key",
secretKey: "your-secret-key",
});
// 标准方式访问
const users = await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();Option 2: pass the configuration directly
const client = createClient({
appCode: "my-app",
accessKey: "your-access-key",
secretKey: "your-secret-key",
models: [
{ datasetCode: "8d2dcbae08b54bdd84c00be558ed48df", tableName: "users", alias: "users" },
{ datasetCode: "a1b2c3d4e5f6789012345678abcdef12", tableName: "analytics", alias: "analytics" },
],
});
// 标准方式访问
const analytics = await client.models.dataset_a1b2c3d4e5f6789012345678abcdef12.filter();Server-side example
// server/lovrabet-client.ts
import { registerModels, createClient } from "@lovrabet/sdk";
registerModels({
appCode: process.env.LOVRABET_APP_CODE,
models: [
{
datasetCode: process.env.USERS_DATASET_CODE,
tableName: "users",
alias: "users",
},
{
datasetCode: process.env.ORDERS_DATASET_CODE,
tableName: "orders",
alias: "orders",
},
],
});
// 使用环境变量中的密钥
export const serverClient = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
secretKey: process.env.LOVRABET_SECRET_KEY,
});
// API 路由中使用
export async function GET() {
try {
// 使用环境变量中的 datasetCode
const users = await serverClient.models[`dataset_${process.env.USERS_DATASET_CODE}`].filter({
currentPage: 1,
pageSize: 100,
});
return Response.json(users);
} catch (error) {
console.error("获取用户数据失败:", error);
return Response.json({ error: "Internal Server Error" }, { status: 500 });
}
}🍪 Cookie authentication (automatic)
If no token or keys are provided, the SDK automatically authenticates with the browser's cookies. This fits browser scenarios where the user is already logged in.
import { createClient } from "@lovrabet/sdk";
import "./api/api"; // 导入 CLI 生成的配置
// 不提供任何认证信息,自动使用 Cookie
const client = createClient();
// 如果用户已登录,会自动使用浏览器中的登录 Cookie
// 标准方式访问
const users = await client.models.dataset_8d2dcbae08b54bdd84c00be558ed48df.filter();
// 或使用别名
const users = await client.models.users.filter();Hybrid authentication strategy
// 优先使用 Token,回退到 Cookie
const createSmartClient = (token?: string) => {
const config = token ? { token } : {}; // 有 token 就用,没有就依赖 Cookie
return createClient(config);
};
// 使用
const tokenFromStorage = localStorage.getItem("auth_token");
const client = createSmartClient(tokenFromStorage);🔄 Switching authentication at runtime
The SDK can update credentials at runtime — no need to recreate the client.
Set a token dynamically
const client = createClient(); // 初始无认证
// 用户登录后,动态设置 token
client.setToken("new-user-token");
// 现在可以访问需要认证的 API
const users = await client.models.users.filter();
// 用户登出时,清除 token
client.setToken(null);A realistic login flow
// auth/auth-manager.ts
import { createClient } from "@lovrabet/sdk";
import "./api"; // 导入预注册的配置
class AuthManager {
private client = createClient(); // 初始化客户端
async login(username: string, password: string) {
try {
// 调用登录 API
const response = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
if (response.ok) {
const { token } = await response.json();
// 设置 token 到 SDK
this.client.setToken(token);
// 存储到本地
localStorage.setItem("auth_token", token);
return { success: true };
} else {
return { success: false, error: "登录失败" };
}
} catch (error) {
return { success: false, error: "网络错误" };
}
}
logout() {
// 清除 SDK 中的 token
this.client.setToken(null);
// 清除本地存储
localStorage.removeItem("auth_token");
// 重定向到登录页
window.location.href = "/login";
}
getClient() {
return this.client;
}
// 初始化时从本地存储恢复 token
init() {
const token = localStorage.getItem("auth_token");
if (token) {
this.client.setToken(token);
}
}
}
export const authManager = new AuthManager();
// 应用启动时初始化
authManager.init();
// 导出客户端供业务代码使用
export const lovrabetClient = authManager.getClient();React hook example
// hooks/useAuth.ts
import { useState, useEffect } from "react";
import { authManager, lovrabetClient } from "../auth/auth-manager";
export function useAuth() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 检查认证状态
const checkAuth = async () => {
try {
// 尝试获取用户信息来验证认证状态
await lovrabetClient.models.users.getOne("me");
setIsAuthenticated(true);
} catch (error) {
setIsAuthenticated(false);
} finally {
setLoading(false);
}
};
checkAuth();
}, []);
const login = async (username: string, password: string) => {
const result = await authManager.login(username, password);
if (result.success) {
setIsAuthenticated(true);
}
return result;
};
const logout = () => {
authManager.logout();
setIsAuthenticated(false);
};
return {
isAuthenticated,
loading,
login,
logout,
client: lovrabetClient,
};
}🛡️ Security best practices
1. Token storage security
// 安全的 Token 存储管理
class SecureTokenStorage {
private readonly TOKEN_KEY = "lovrabet_auth_token";
setToken(token: string) {
// 生产环境建议使用 httpOnly cookie 或其他安全存储方案
if (process.env.NODE_ENV === "production") {
// 设置安全的 cookie
document.cookie = `${this.TOKEN_KEY}=${token}; secure; httpOnly; samesite=strict`;
} else {
// 开发环境使用 localStorage
localStorage.setItem(this.TOKEN_KEY, token);
}
}
getToken(): string | null {
if (process.env.NODE_ENV === "production") {
// 从 cookie 中读取
const cookies = document.cookie.split(";");
const tokenCookie = cookies.find(c => c.trim().startsWith(this.TOKEN_KEY));
return tokenCookie ? tokenCookie.split("=")[1] : null;
} else {
return localStorage.getItem(this.TOKEN_KEY);
}
}
removeToken() {
if (process.env.NODE_ENV === "production") {
document.cookie = `${this.TOKEN_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
} else {
localStorage.removeItem(this.TOKEN_KEY);
}
}
}2. Managing environment variables
// .env.example
LOVRABET_APP_CODE=your-app-code
LOVRABET_ACCESS_KEY=your-access-key
LOVRABET_SECRET_KEY=your-secret-key
// config/lovrabet.ts
export const lovrabetConfig = {
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY,
secretKey: process.env.LOVRABET_SECRET_KEY,
};
// 验证必要的环境变量
if (!lovrabetConfig.appCode) {
throw new Error("LOVRABET_APP_CODE is required");
}3. Error handling and retries
const client = createClient({
token: "user-token",
options: {
timeout: 30000,
onError: (error) => {
console.error("Lovrabet SDK Error:", {
message: error.message,
status: error.status,
url: error.url,
});
// 根据错误类型进行不同处理
if (error.status === 401) {
// 认证失败
console.log("Authentication failed, redirecting to login...");
authManager.logout();
} else if (error.status >= 500) {
// 服务器错误,可以考虑重试
console.log("Server error, may retry later");
}
},
},
});🔍 Debugging authentication issues
Inspect the current configuration
const client = createClient({ token: "your-token" });
// 获取当前配置(不包含敏感信息)
const config = client.getConfig();
console.log("当前配置:", {
appCode: config.appCode,
env: config.env,
hasToken: !!config.token,
hasAccessKey: !!config.accessKey,
serverUrl: config.serverUrl,
});Check whether authentication is valid
// 检测认证是否有效
const checkAuthStatus = async (client) => {
try {
// 尝试调用一个需要认证的 API
await client.models.users.filter({ pageSize: 1 });
console.log("✅ 认证有效");
return true;
} catch (error) {
if (error.status === 401) {
console.log("❌ 认证无效或已过期");
} else {
console.log("❓ 其他错误:", error.message);
}
return false;
}
};📖 Next steps
With authentication configured, you can continue with:
- 📊 API guide - dive deeper into API operations
- 🎯 TypeScript support - a type-safe development experience
- 🛠️ Practical examples - React/Vue integration examples
❓ FAQ
Q: What is the difference between a token and OpenAPI keys?
- Token: user-level authentication, suited to frontend apps and user-scoped operations
- OpenAPI keys: app-level authentication, suited to server-to-server calls, with higher privileges
Q: How do I handle token expiration?
const client = createClient({
token: "initial-token",
options: {
onError: async (error) => {
if (error.status === 401) {
// Token 可能过期,尝试刷新
try {
const newToken = await refreshToken();
client.setToken(newToken);
// 可以选择重试原始请求
} catch (refreshError) {
// 刷新失败,跳转到登录页
window.location.href = "/login";
}
}
},
},
});Q: How do I use the SDK in Node.js?
For Node.js environments, OpenAPI key authentication is recommended:
// server/lovrabet.js
const { registerModels, createClient } = require("@lovrabet/sdk");
registerModels({
appCode: process.env.LOVRABET_APP_CODE,
models: [
{ datasetCode: process.env.USERS_DATASET_CODE, tableName: "users", alias: "users" },
],
});
const client = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
secretKey: process.env.LOVRABET_SECRET_KEY,
});
module.exports = { client };Next steps
- 📋 Configuration - learn about the various configuration methods
- 📊 API guide - dive deeper into API operations
- 🛠️ Practical examples - React/Vue integration examples