Framework-agnostic usage of the 23blocks SDK. Works with any JavaScript environment.
npm install @23blocks/sdkThe simplest way to use the SDK with automatic token management:
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { authentication: 'https://api.yourapp.com' },
apiKey: 'your-api-key',
});
// Sign in - tokens are stored automatically
const { user } = await client.auth.signIn({
email: 'user@example.com',
password: 'password',
});
console.log('Welcome', user.email);
// All requests now include auth automatically
const results = await client.search.search.search({
query: 'hello world',
limit: 10,
});
const products = await client.products.products.list({ limit: 20 });
// Sign out - tokens are cleared automatically
await client.auth.signOut();Tokens are stored in localStorage and attached to requests automatically:
const client = create23BlocksClient({
urls: { authentication: 'https://api.yourapp.com' },
apiKey: 'your-api-key',
// authMode: 'token', // default
// storage: 'localStorage', // 'sessionStorage' | 'memory'
});Backend manages authentication via httpOnly cookies:
const client = create23BlocksClient({
urls: { authentication: 'https://api.yourapp.com' },
apiKey: 'your-api-key',
authMode: 'cookie',
});
// Sign in - backend sets httpOnly cookie
await client.auth.signIn({ email, password });
// Requests automatically include cookies
const products = await client.products.products.list();For server-side rendering, use memory storage and pass tokens manually:
const client = create23BlocksClient({
urls: { authentication: 'https://api.yourapp.com' },
apiKey: 'your-api-key',
storage: 'memory',
headers: {
Authorization: `Bearer ${tokenFromRequest}`,
},
});const client = create23BlocksClient({
urls: { authentication: 'https://api.yourapp.com' },
apiKey: 'your-api-key',
tenantId: 'tenant-123',
});// Check if authenticated (token mode only)
const isLoggedIn = client.isAuthenticated();
// Get tokens manually
const accessToken = client.getAccessToken();
const refreshToken = client.getRefreshToken();
// Set tokens manually (useful for SSR hydration)
client.setTokens(accessToken, refreshToken);
// Clear session
client.clearSession();For advanced use cases requiring custom transport configuration:
npm install @23blocks/transport-http @23blocks/block-authentication @23blocks/block-searchimport { createHttpTransport } from '@23blocks/transport-http';
const transport = createHttpTransport({
baseUrl: 'https://api.yourapp.com',
headers: () => {
const token = localStorage.getItem('access_token');
return token ? { Authorization: `Bearer ${token}` } : {};
},
});import { createAuthenticationBlock } from '@23blocks/block-authentication';
import { createSearchBlock } from '@23blocks/block-search';
const auth = createAuthenticationBlock(transport, {
apiKey: 'your-api-key',
});
const search = createSearchBlock(transport, {
apiKey: 'your-api-key',
});// Sign in
const { user, accessToken } = await auth.auth.signIn({
email: 'user@example.com',
password: 'password',
});
localStorage.setItem('access_token', accessToken);
console.log('Welcome', user.email);
// Search
const results = await search.search.search({
query: 'hello world',
limit: 10,
});
console.log(results.data);const transport = createHttpTransport({
baseUrl: 'https://api.yourapp.com',
});const transport = createHttpTransport({
baseUrl: 'https://api.yourapp.com',
headers: () => ({
Authorization: `Bearer ${getAccessToken()}`,
'X-Custom-Header': 'value',
}),
});const transport = createHttpTransport({
baseUrl: 'https://api.yourapp.com',
retry: {
maxRetries: 3,
retryDelay: 1000,
retryOn: [500, 502, 503, 504],
},
});const transport = createHttpTransport({
baseUrl: 'https://api.yourapp.com',
timeout: 30000, // 30 seconds
});Every block exposes a health() method to verify service connectivity before making real API calls:
const status = await client.authentication.health();
console.log(status);
// { service: "auth", status: "ok", version: "v4.4.0", timestamp: "2026-02-16T23:19:52Z" }
// Check multiple services in parallel
const results = await Promise.all([
client.authentication.health(),
client.search.health(),
client.products.health(),
]);
results.forEach((r) => console.log(`${r.service}: ${r.status}`));With standalone blocks:
const auth = createAuthenticationBlock(transport, { apiKey: 'your-api-key' });
const status = await auth.health();const auth = createAuthenticationBlock(transport, { apiKey: 'your-api-key' });
try {
const { user, accessToken, refreshToken } = await auth.auth.signIn({
email: 'user@example.com',
password: 'password',
});
// Store tokens
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', refreshToken);
console.log('Signed in as', user.email);
} catch (error) {
if (isBlockErrorException(error)) {
console.error('Sign in failed:', error.message);
}
}const { user, accessToken } = await auth.auth.signUp({
email: 'newuser@example.com',
password: 'securepassword',
firstName: 'John',
lastName: 'Doe',
});// Request reset
await auth.auth.requestPasswordReset({
email: 'user@example.com',
});
// Complete reset (with token from email)
await auth.auth.resetPassword({
token: 'reset-token-from-email',
password: 'newpassword',
});const refreshToken = localStorage.getItem('refresh_token');
const { accessToken, refreshToken: newRefreshToken } = await auth.auth.refreshToken({
refreshToken,
});
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', newRefreshToken);Pass oauthMode: true to receive an OAuth 2.0 token pair (access + refresh tokens) from Google or Facebook login:
const { user, accessToken, refreshToken } = await auth.oauth.googleLogin({
token: googleIdToken,
oauthMode: true,
});
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', refreshToken!);const user = await auth.users.me();
console.log(user.email, user.firstName, user.lastName);Create JWT tokens for AI agents and backend services:
const auth = createAuthenticationBlock(transport, { apiKey: 'your-api-key' });
// Create a short-lived token for an AI agent (1-24h)
const agentToken = await auth.serviceTokens.create({
name: 'support-chatbot',
tokenCategory: 'agent',
scopes: ['conversations:read', 'conversations:write'],
expiresInDays: 1,
});
// agentToken.jwt - store immediately, only returned once
// Create a long-lived token for a backend service (30-365 days)
const svcToken = await auth.serviceTokens.create({
name: 'billing-sync',
tokenCategory: 'service',
scopes: ['wallet:read', 'crm:write'],
expiresInDays: 90,
});
// List all tokens with pagination
const tokens = await auth.serviceTokens.list({ page: 1, perPage: 50 });
// Get a specific token (JWT is NOT included in get/list responses)
const token = await auth.serviceTokens.get('token-unique-id');
console.log(token.active, token.useCount, token.lastUsedAt);
// Regenerate a compromised token (old JWT is invalidated)
const newToken = await auth.serviceTokens.regenerate('token-unique-id');
// newToken.jwt - new JWT, store immediately
// Revoke a token
await auth.serviceTokens.revoke('token-unique-id');const search = createSearchBlock(transport, { apiKey: 'your-api-key' });
const results = await search.search.search({
query: 'product name',
limit: 20,
offset: 0,
});
results.data.forEach((item) => {
console.log(item.id, item.title, item.score);
});const results = await search.search.search({
query: 'laptop',
filters: {
category: 'electronics',
priceMin: 500,
priceMax: 2000,
},
sort: { field: 'price', direction: 'asc' },
limit: 10,
});// Add favorite
await search.favorites.create({
favoriteableId: 'product-123',
favoriteableType: 'Product',
});
// List favorites
const favorites = await search.favorites.list({ limit: 50 });
// Remove favorite
await search.favorites.delete('favorite-id');import { createProductsBlock } from '@23blocks/block-products';
const products = createProductsBlock(transport, { apiKey: 'your-api-key' });
// List products
const { data, meta } = await products.products.list({
limit: 20,
sort: { field: 'createdAt', direction: 'desc' },
});
console.log(`Found ${meta.total} products`);
// Get single product
const product = await products.products.get('product-id');
// List categories
const categories = await products.categories.list();
// Get product variants
const variants = await products.variants.listByProduct('product-id');import { BlockErrorException, isBlockErrorException, ErrorCodes } from '@23blocks/contracts';
try {
await auth.auth.signIn({ email, password });
} catch (error) {
if (isBlockErrorException(error)) {
// Typed error with code, message, and optional details
console.error('Error code:', error.code);
console.error('Message:', error.message);
switch (error.code) {
case ErrorCodes.INVALID_CREDENTIALS:
showError('Invalid email or password');
break;
case ErrorCodes.ACCOUNT_LOCKED:
showError('Account locked. Contact support.');
break;
case ErrorCodes.NETWORK_ERROR:
showError('Network error. Please try again.');
break;
default:
showError(error.message);
}
} else {
// Unknown error
throw error;
}
}import type { PageResult, ListParams } from '@23blocks/contracts';
async function fetchAllProducts(): Promise<Product[]> {
const allProducts: Product[] = [];
let offset = 0;
const limit = 100;
while (true) {
const { data, meta } = await products.products.list({ limit, offset });
allProducts.push(...data);
if (allProducts.length >= meta.total) {
break;
}
offset += limit;
}
return allProducts;
}For larger applications, wrap blocks in a service layer:
// services/api.ts
import { createHttpTransport } from '@23blocks/transport-http';
import { createAuthenticationBlock } from '@23blocks/block-authentication';
import { createSearchBlock } from '@23blocks/block-search';
import { createProductsBlock } from '@23blocks/block-products';
const transport = createHttpTransport({
baseUrl: import.meta.env.VITE_API_URL,
headers: () => {
const token = localStorage.getItem('access_token');
return token ? { Authorization: `Bearer ${token}` } : {};
},
});
const config = { apiKey: import.meta.env.VITE_API_KEY };
export const api = {
auth: createAuthenticationBlock(transport, config),
search: createSearchBlock(transport, config),
products: createProductsBlock(transport, config),
};
// Usage
import { api } from './services/api';
await api.auth.auth.signIn({ email, password });
const results = await api.search.search.search({ query: 'test' });All types are exported from each package:
import type {
User,
SignInRequest,
SignInResponse,
Company,
ApiKey,
ServiceToken,
ServiceTokenWithJwt,
CreateServiceTokenRequest,
} from '@23blocks/block-authentication';
import type {
SearchResult,
Favorite,
} from '@23blocks/block-search';
import type {
Product,
Category,
Variant,
} from '@23blocks/block-products';
import type {
Transport,
BlockError,
PageResult,
ListParams,
} from '@23blocks/contracts';The SDK works in Node.js environments:
// server.ts
import { createHttpTransport } from '@23blocks/transport-http';
import { createAuthenticationBlock } from '@23blocks/block-authentication';
const transport = createHttpTransport({
baseUrl: process.env.API_URL!,
headers: () => ({
'X-Api-Key': process.env.API_KEY!,
}),
});
const auth = createAuthenticationBlock(transport, {
apiKey: process.env.API_KEY!,
});
// Use in your server routes
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const result = await auth.auth.signIn({ email, password });
res.json(result);
});