logto-auth-node-sdk
v1.0.0
Published
A comprehensive Logto authentication client library with circuit breaker pattern support
Downloads
8
Maintainers
Readme
Logto Auth Node.js SDK
A comprehensive TypeScript/JavaScript SDK for Logto - Modern auth infrastructure for developers. This SDK provides seamless integration with both Logto Cloud and self-hosted Logto OSS instances, featuring built-in resilience patterns and comprehensive API coverage.
About Logto
Logto is a modern authentication and user management solution designed for developers. It offers:
- 🔐 Complete Authentication Solution - Sign-in, sign-up, profile management, and more
- 🌐 Multi-tenant Support - Organizations and role-based access control
- 🎨 Customizable UI - Pre-built sign-in experience with full customization options
- 🔌 Multiple Deployment Options - Cloud-hosted or self-hosted OSS
- 📱 Cross-platform - Web, mobile, and API applications
- 🛡️ Enterprise Ready - SSO, SCIM, audit logs, and compliance features
Features
- 🚀 Full Logto API Coverage - Users, Organizations, Authentication, and Management APIs
- 🔄 Built-in Circuit Breaker - Enhanced resilience and fault tolerance
- 🛡️ Automatic Token Management - Token refresh and secure storage
- 🔁 Smart Retry Logic - Exponential backoff with jitter
- 💪 TypeScript First - Full type definitions and IntelliSense support
- 📊 Circuit Breaker Monitoring - Real-time status and management
- ⚡ Lightweight - Minimal dependencies, maximum performance
- 🌩️ Multi-Environment - Supports both Logto Cloud and self-hosted instances
Installation
npm install logto-auth-node-sdkyarn add logto-auth-node-sdkpnpm add logto-auth-node-sdkQuick Start
Logto Cloud Setup
import { LogtoClient } from 'logto-auth-node-sdk';
const client = new LogtoClient({
authEndpoint: 'https://your-tenant.logto.app',
appId: 'your-app-id',
appSecret: 'your-app-secret',
resourceEndpoint: 'https://your-tenant.logto.app/api',
});Self-hosted Logto OSS Setup
import { LogtoClient } from 'logto-auth-node-sdk';
const client = new LogtoClient({
authEndpoint: 'https://your-logto-instance.com',
appId: 'your-app-id',
appSecret: 'your-app-secret',
resourceEndpoint: 'https://your-logto-instance.com/api',
});Basic Usage
// Create a user
const user = await client.createUser({
username: 'john_doe',
primaryEmail: '[email protected]',
name: 'John Doe',
password: 'secure-password'
});
// Create an organization
const org = await client.createOrganization({
name: 'Acme Corporation',
description: 'A sample organization'
});
// Add user to organization
await client.addUsersToOrganization(org.id, {
userIds: [user.id]
});Getting Started with Logto
Logto Cloud
- Sign up at Logto Cloud
- Create a new application
- Get your App ID and App Secret from the application settings
- Use your tenant endpoint:
https://{your-tenant}.logto.app
Self-hosted Logto OSS
For self-hosted deployment, follow the Logto OSS deployment guide:
Docker Deployment
# Clone the repository
git clone https://github.com/logto-io/logto.git
cd logto
# Start with Docker Compose
docker compose up -dManual Deployment
# Install dependencies
npm install
# Build the project
npm run build
# Set environment variables
export DB_URL=postgresql://username:password@localhost:5432/logto
export PORT=3001
# Start the application
npm startConfiguration
LogtoConfig Interface
interface LogtoConfig {
/** Your Logto instance URL (Cloud: https://{tenant}.logto.app, OSS: your domain) */
authEndpoint: string;
/** Application ID from Logto console */
appId: string;
/** Application secret from Logto console */
appSecret: string;
/** Resource endpoint URL */
resourceEndpoint: string;
/** Request timeout in milliseconds (default: 10000) */
timeout?: number;
/** Circuit breaker configuration */
circuitBreakerOptions?: CircuitBreakerOptions;
/** Custom headers for requests */
headers?: Record<string, string>;
/** Enable debug logging */
debug?: boolean;
}Circuit Breaker Options
interface CircuitBreakerOptions {
/** Number of failures before opening circuit (default: 5) */
failureThreshold: number;
/** Time in ms before attempting to close circuit (default: 30000) */
resetTimeout: number;
/** Number of retries in half-open state (default: 2) */
halfOpenRetries: number;
/** Enable circuit breaker monitoring */
monitoring?: boolean;
}API Reference
User Management
Create User
interface CreateUserRequest {
username?: string;
primaryEmail?: string;
primaryPhone?: string;
name?: string;
avatar?: string;
customData?: Record<string, any>;
profile?: UserProfile;
password?: string;
}
const user = await client.createUser({
username: 'john_doe',
primaryEmail: '[email protected]',
name: 'John Doe',
password: 'secure-password',
customData: {
department: 'Engineering',
role: 'Developer'
}
});Get User
const user = await client.getUser(userId);Update User
const updatedUser = await client.updateUser(userId, {
name: 'John Smith',
avatar: 'https://example.com/avatar.jpg',
customData: {
role: 'Senior Developer'
}
});User Password Management
// Update password
await client.updateUserPassword(userId, {
password: 'new-secure-password'
});
// Verify password
const isValid = await client.verifyUserPassword(userId, {
password: 'password-to-check'
});User Status Management
// Suspend user
await client.updateUserSuspensionStatus(userId, {
isSuspended: true
});
// Reactivate user
await client.updateUserSuspensionStatus(userId, {
isSuspended: false
});Delete User
await client.deleteUser(userId);Organization Management
Create Organization
const organization = await client.createOrganization({
name: 'Acme Corporation',
description: 'Leading technology company',
customData: {
tier: 'enterprise',
industry: 'technology'
}
});Get Organization
const org = await client.getOrganization(organizationId);Update Organization
const updatedOrg = await client.updateOrganization(organizationId, {
name: 'Acme Corp Ltd',
description: 'Updated description',
customData: {
tier: 'premium'
}
});Organization User Management
// Add users to organization
await client.addUsersToOrganization(organizationId, {
userIds: ['user1', 'user2', 'user3']
});
// Remove user from organization
await client.removeUserFromOrganization(organizationId, userId);Delete Organization
await client.deleteOrganization(organizationId);Advanced Features
Circuit Breaker Management
Monitor and manage circuit breakers for enhanced reliability:
// Get circuit breaker status
const status = client.getCircuitBreakerStatus('logto-users');
console.log(`Circuit: ${status.name}, State: ${status.state}`);
// Get all circuit breakers
const allCircuits = client.getAllCircuitBreakers();
for (const [name, circuit] of allCircuits) {
console.log(`${name}: ${circuit.state} (Failures: ${circuit.failureCount})`);
}
// Reset circuit breaker
client.resetCircuitBreaker('logto-users');Error Handling
import { LogtoError, CircuitBreakerError } from 'logto-auth-node-sdk';
try {
const user = await client.getUser('invalid-user-id');
} catch (error) {
if (error instanceof CircuitBreakerError) {
console.log('Service temporarily unavailable, please try again later');
} else if (error instanceof LogtoError) {
console.log(`Logto API error: ${error.message} (Status: ${error.status})`);
} else {
console.log('Unexpected error:', error.message);
}
}Token Management
The SDK automatically handles token lifecycle:
// Tokens are automatically managed
const user = await client.getUser(userId); // Token obtained if needed
const org = await client.getOrganization(orgId); // Reuses existing token
// Manual token refresh (rarely needed)
await client.refreshToken();Environment Configuration
Environment Variables
# Logto Configuration
LOGTO_AUTH_ENDPOINT=https://your-tenant.logto.app
LOGTO_APP_ID=your-app-id
LOGTO_APP_SECRET=your-app-secret
LOGTO_RESOURCE_ENDPOINT=https://your-tenant.logto.app/api
# Optional Configuration
LOGTO_TIMEOUT=10000
LOGTO_DEBUG=falseConfiguration from Environment
import { LogtoClient } from 'logto-auth-node-sdk';
const client = new LogtoClient({
authEndpoint: process.env.LOGTO_AUTH_ENDPOINT!,
appId: process.env.LOGTO_APP_ID!,
appSecret: process.env.LOGTO_APP_SECRET!,
resourceEndpoint: process.env.LOGTO_RESOURCE_ENDPOINT!,
timeout: parseInt(process.env.LOGTO_TIMEOUT || '10000'),
debug: process.env.LOGTO_DEBUG === 'true'
});Examples
Complete User Management Example
import { LogtoClient } from 'logto-auth-node-sdk';
const client = new LogtoClient({
authEndpoint: process.env.LOGTO_AUTH_ENDPOINT!,
appId: process.env.LOGTO_APP_ID!,
appSecret: process.env.LOGTO_APP_SECRET!,
resourceEndpoint: process.env.LOGTO_RESOURCE_ENDPOINT!,
});
async function userManagementExample() {
try {
// Create user
const user = await client.createUser({
username: 'alice_smith',
primaryEmail: '[email protected]',
name: 'Alice Smith',
password: 'SecurePassword123!',
customData: {
role: 'developer',
department: 'engineering',
startDate: new Date().toISOString()
}
});
console.log('Created user:', user.id);
// Verify password
const isValidPassword = await client.verifyUserPassword(user.id, {
password: 'SecurePassword123!'
});
console.log('Password valid:', isValidPassword);
// Update user profile
const updatedUser = await client.updateUser(user.id, {
name: 'Alice Johnson', // Married name
customData: {
...user.customData,
role: 'senior-developer' // Promotion
}
});
console.log('Updated user:', updatedUser.name);
// Temporarily suspend user
await client.updateUserSuspensionStatus(user.id, {
isSuspended: true
});
console.log('User suspended');
// Reactivate user
await client.updateUserSuspensionStatus(user.id, {
isSuspended: false
});
console.log('User reactivated');
} catch (error) {
console.error('User management error:', error);
}
}Organization and Team Management
async function organizationExample() {
try {
// Create organization
const organization = await client.createOrganization({
name: 'Tech Innovations Inc',
description: 'A forward-thinking technology company',
customData: {
tier: 'enterprise',
industry: 'software',
founded: '2024',
size: 'medium'
}
});
console.log('Created organization:', organization.id);
// Create team members
const teamMembers = await Promise.all([
client.createUser({
username: 'john_lead',
primaryEmail: '[email protected]',
name: 'John Smith',
password: 'LeaderPass123!',
customData: { role: 'team-lead' }
}),
client.createUser({
username: 'sarah_dev',
primaryEmail: '[email protected]',
name: 'Sarah Connor',
password: 'DevPass123!',
customData: { role: 'developer' }
}),
client.createUser({
username: 'mike_designer',
primaryEmail: '[email protected]',
name: 'Mike Johnson',
password: 'DesignPass123!',
customData: { role: 'designer' }
})
]);
console.log(`Created ${teamMembers.length} team members`);
// Add all users to organization
await client.addUsersToOrganization(organization.id, {
userIds: teamMembers.map(user => user.id)
});
console.log('Added users to organization');
// Update organization details
const updatedOrg = await client.updateOrganization(organization.id, {
description: 'A rapidly growing technology company specializing in innovative solutions',
customData: {
...organization.customData,
size: 'large', // Company grew
employees: teamMembers.length
}
});
console.log('Updated organization:', updatedOrg.name);
// Remove one user (they left the company)
await client.removeUserFromOrganization(organization.id, teamMembers[2].id);
console.log('Removed user from organization');
} catch (error) {
console.error('Organization management error:', error);
}
}Error Handling and Resilience
import { LogtoClient, CircuitBreakerError, LogtoError } from 'logto-auth-node-sdk';
const client = new LogtoClient({
authEndpoint: process.env.LOGTO_AUTH_ENDPOINT!,
appId: process.env.LOGTO_APP_ID!,
appSecret: process.env.LOGTO_APP_SECRET!,
resourceEndpoint: process.env.LOGTO_RESOURCE_ENDPOINT!,
circuitBreakerOptions: {
failureThreshold: 3,
resetTimeout: 60000,
halfOpenRetries: 1,
monitoring: true
}
});
async function resilientOperations() {
// Monitor circuit breaker health
setInterval(() => {
const circuits = client.getAllCircuitBreakers();
for (const [name, circuit] of circuits) {
if (circuit.state !== 'CLOSED') {
console.warn(`Circuit breaker ${name} is ${circuit.state}`);
}
}
}, 30000);
// Perform operations with error handling
async function safeUserOperation(userId: string) {
try {
const user = await client.getUser(userId);
return { success: true, data: user };
} catch (error) {
if (error instanceof CircuitBreakerError) {
console.log('Service temporarily unavailable - circuit breaker open');
return { success: false, reason: 'service_unavailable', retry: true };
} else if (error instanceof LogtoError) {
console.log(`API error: ${error.message} (${error.status})`);
return { success: false, reason: 'api_error', retry: error.status >= 500 };
} else {
console.error('Unexpected error:', error);
return { success: false, reason: 'unknown_error', retry: false };
}
}
}
// Use the safe operation
const result = await safeUserOperation('user-123');
if (!result.success && result.retry) {
// Implement your retry logic here
setTimeout(() => safeUserOperation('user-123'), 5000);
}
}TypeScript Support
The SDK is built with TypeScript and provides comprehensive type definitions:
import {
LogtoClient,
LogtoConfig,
UserResponse,
OrganizationResponse,
CreateUserRequest,
CreateOrganizationRequest,
CircuitBreakerStatus,
CircuitState
} from 'logto-auth-node-sdk';
// Fully typed configuration
const config: LogtoConfig = {
authEndpoint: 'https://your-tenant.logto.app',
appId: 'app-id',
appSecret: 'app-secret',
resourceEndpoint: 'https://your-tenant.logto.app/api'
};
// Typed client instance
const client: LogtoClient = new LogtoClient(config);
// Typed responses
const user: UserResponse = await client.getUser('user-id');
const org: OrganizationResponse = await client.getOrganization('org-id');
// Typed request objects
const createUserRequest: CreateUserRequest = {
username: 'john_doe',
primaryEmail: '[email protected]',
name: 'John Doe'
};Performance and Best Practices
Connection Pooling
// Create a single client instance and reuse it
const client = new LogtoClient(config);
// Don't create new clients for each request
// ❌ Bad
async function badExample() {
const client = new LogtoClient(config);
return client.getUser('user-id');
}
// ✅ Good
async function goodExample(client: LogtoClient) {
return client.getUser('user-id');
}Batch Operations
// Process multiple users efficiently
async function batchUserCreation(userData: CreateUserRequest[]) {
const users = await Promise.all(
userData.map(data => client.createUser(data))
);
return users;
}
// Add multiple users to organization in one call
await client.addUsersToOrganization(orgId, {
userIds: users.map(u => u.id)
});Circuit Breaker Monitoring
// Set up monitoring
function setupMonitoring(client: LogtoClient) {
setInterval(() => {
const circuits = client.getAllCircuitBreakers();
for (const [name, circuit] of circuits) {
if (circuit.failureCount > 0) {
console.log(`Circuit ${name}: ${circuit.failureCount} failures`);
}
if (circuit.state === 'OPEN') {
// Alert your monitoring system
console.error(`Circuit breaker ${name} is OPEN - service degraded`);
}
}
}, 60000); // Check every minute
}Deployment Considerations
Logto Cloud vs Self-hosted
| Feature | Logto Cloud | Self-hosted OSS | |---------|-------------|-----------------| | Setup | Instant signup | Manual deployment | | Maintenance | Fully managed | Self-managed | | Scaling | Auto-scaling | Manual scaling | | Updates | Automatic | Manual updates | | Customization | Limited | Full control | | Cost | Usage-based pricing | Infrastructure costs | | Support | Official support | Community support |
Environment-specific Configuration
// Development
const devClient = new LogtoClient({
authEndpoint: 'http://localhost:3001',
appId: 'dev-app-id',
appSecret: 'dev-app-secret',
resourceEndpoint: 'http://localhost:3001/api',
debug: true
});
// Production
const prodClient = new LogtoClient({
authEndpoint: 'https://your-tenant.logto.app',
appId: process.env.LOGTO_APP_ID!,
appSecret: process.env.LOGTO_APP_SECRET!,
resourceEndpoint: 'https://your-tenant.logto.app/api',
timeout: 5000,
circuitBreakerOptions: {
failureThreshold: 5,
resetTimeout: 30000,
halfOpenRetries: 2
}
});Troubleshooting
Common Issues
Authentication Errors
// Check your app credentials console.log('App ID:', process.env.LOGTO_APP_ID); console.log('Endpoint:', process.env.LOGTO_AUTH_ENDPOINT); // Verify endpoint format // ✅ Correct: https://your-tenant.logto.app // ❌ Wrong: https://your-tenant.logto.app/Circuit Breaker Issues
// Reset circuit breaker client.resetCircuitBreaker('logto-users'); // Check circuit status const status = client.getCircuitBreakerStatus('logto-users'); console.log('Circuit state:', status.state);Network Timeouts
// Increase timeout for slow networks const client = new LogtoClient({ ...config, timeout: 30000 // 30 seconds });
Debug Mode
const client = new LogtoClient({
...config,
debug: true // Enables detailed logging
});Migration Guide
From v0.x to v1.x
// v1.x (New)
import { LogtoClient } from 'logto-auth-node-sdk';Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/logto-io/logto-auth-node-sdk.git
cd logto-auth-node-sdk
# Install dependencies
npm install
# Run tests
npm test
# Build the project
npm run build
# Run linting
npm run lintRunning Tests
# Unit tests
npm run test:unit
# Integration tests (requires Logto instance)
npm run test:integration
# Coverage report
npm run test:coverageLicense
This project is licensed under the MIT License - see the LICENSE file for details.
Support and Resources
Documentation
Community
Commercial Support
- Logto Cloud - Managed Logto service
- Enterprise Support - Priority support and consulting
Changelog
1.0.0
- 🎉 Initial Release
- ✨ Complete Logto API coverage
- 🔄 Circuit breaker implementation
- 🛡️ Automatic token management
- 💪 Full TypeScript support
- 📊 Circuit breaker monitoring
- 🌩️ Multi-environment support (Cloud + OSS)
- 📚 Comprehensive documentation
Made with ❤️ for the Logto community
Logto Auth Node.js SDK - Bringing modern authentication to your Node.js applications
