Skip to content

JavaScript SDK Documentation

The Sharokey JavaScript library allows easy integration of secure secret sharing into your JavaScript/TypeScript applications. It reproduces all Sharokey CLI functionality with a modern and intuitive API.

✨ Key Features

  • 🔐 Zero Knowledge Encryption: Client-side AES-GCM-256
  • 🌍 Multi-environment: Node.js and browsers
  • 📱 Modern API: Promises, async/await, TypeScript
  • 🔑 Authentication: API Token via Laravel Sanctum
  • 📎 File Attachments: Support for encrypted files (max 10 files, 10MB total)
  • 🎛️ Advanced Configuration: Retry, timeout, logs
  • 🧪 Complete Testing: Coverage and validation

📦 Installation

⚠️ Important Note: This package is not yet available on NPM. This documentation describes the future API based on existing implementation.

NPM (Coming Soon)

bash
# Not yet available
# npm install sharokey-js

Yarn (Coming Soon)

bash
# Not yet available
# yarn add sharokey-js

CDN (Browser) - Not Yet Available

html
<!-- Not yet available -->
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/sharokey.min.js"></script> -->

🚀 Quick Start

ES6/TypeScript Import

javascript
import { SharokeyClient } from 'sharokey-js';
// or
import SharokeyClient from 'sharokey-js';

CommonJS Require

javascript
const { SharokeyClient } = require('sharokey-js');

Basic Usage

javascript
// Client configuration
const client = new SharokeyClient({
  token: 'your-api-token',
  apiUrl: 'https://api.sharokey.com/api/v1'
});

// Create a secret
const secret = await client.createSecret({
  content: "My secret password",
  expirationHours: 24,
  maximumViews: 1,
  description: "Temporary access"
});

console.log('Secret created:', secret.shareUrl);
console.log('Expires on:', secret.expiration);

⚙️ Configuration

Basic Configuration

javascript
const client = new SharokeyClient({
  token: 'your-api-token',                     // REQUIRED
  apiUrl: 'https://api.sharokey.com/api/v1', // Optional
  timeout: 30000,                              // 30 seconds
  retries: 3                                   // 3 retries
});

Advanced Configuration

javascript
const client = new SharokeyClient({
  token: 'your-api-token',
  apiUrl: 'https://api.sharokey.com/api/v1',
  timeout: 60000,
  retries: 5,
  defaultExpirationHours: 48,
  defaultMaximumViews: 3,
  logLevel: 'info',                    // debug, info, warn, error
  validateSsl: true,
  headers: {
    'X-Custom-Header': 'value'
  }
});

Configuration Validation

javascript
import { validateConfig } from 'sharokey-js';

const errors = validateConfig({
  token: 'test',
  timeout: -1  // Error
});

if (errors.length > 0) {
  console.error('Configuration errors:', errors);
}

🔑 Authentication

With API Token

javascript
const client = new SharokeyClient({
  token: 'sk_live_abcdefghijklmnop1234567890'
});

// Validate token
const userInfo = await client.validateToken();
if (userInfo) {
  console.log('Connected as:', userInfo.email);
} else {
  console.error('Invalid token');
}

Connectivity Test

javascript
const isConnected = await client.testConnection();
if (!isConnected) {
  throw new Error('Unable to connect to Sharokey API');
}

User Information

javascript
const user = client.getCurrentUser();
console.log('Current user:', user);

📝 Creating Secrets

Simple Creation

javascript
const secret = await client.createSecret("My secret");
console.log('Share link:', secret.shareUrl);

Creation with Options

javascript
const secret = await client.createSecret({
  content: "Confidential information",
  description: "Important client data",
  message: "Please review before tomorrow",
  expirationHours: 48,
  maximumViews: 3,
  password: "additional-protection"
});

With File Attachments

javascript
import fs from 'fs';

const fileData = fs.readFileSync('document.pdf');

const secret = await client.createSecret({
  content: "Here is the requested document",
  description: "Confidential contract",
  expirationHours: 72,
  maximumViews: 1,
  attachments: [
    {
      name: 'contract.pdf',
      data: fileData
    },
    {
      name: 'annex.docx', 
      data: annexData
    }
  ]
});

With OTP Protection

javascript
const secret = await client.createSecret({
  content: "Critical access code",
  expirationHours: 1,
  maximumViews: 1,
  otpEmail: "[email protected]",
  // or (mutually exclusive)
  otpPhone: "+33123456789"
});

Password Generator

javascript
// Generate a simple password
const password = client.generatePassword();
console.log('Generated password:', password);

// Generate and create a secret
const result = await client.createPasswordSecret(
  "Temporary server access", 
  {
    passwordLength: 20,
    includeSymbols: true,
    expirationHours: 2,
    maximumViews: 1
  }
);

console.log('Password:', result.password);
console.log('Link:', result.secret.shareUrl);

🛡️ Advanced Security Options

CAPTCHA Protection

javascript
// Enable CAPTCHA verification
const secret = await client.createSecret({
  content: "Sensitive information",
  expirationHours: 2,
  maximumViews: 1,
  captcha: true,
  description: "CAPTCHA protected secret"
});

IP Whitelist Restrictions

javascript
// Restrict access to specific IPs
const secret = await client.createSecret({
  content: "Internal documentation",
  expirationHours: 24,
  maximumViews: 5,
  ipWhitelist: "192.168.1.100,10.0.0.0/24,203.0.113.5", // Max 255 characters
  description: "Only accessible from office network"
});

Geolocation Restrictions

javascript
// Restrict access to specific countries
const secret = await client.createSecret({
  content: "Regional configuration data",
  expirationHours: 12,
  maximumViews: 3,
  geolocation: "FR,DE,BE,NL,IT,ES", // Max 255 characters
  description: "European Union only access"
});

Combined Security (Maximum Protection)

javascript
// Use all security features together
const secret = await client.createSecret({
  content: "Top secret information",
  expirationHours: 1,
  maximumViews: 1,
  description: "Maximum security secret",
  message: "Handle with extreme care - contains sensitive data",
  password: "extra-secure-password",
  captcha: true,
  ipWhitelist: "192.168.1.0/24",
  geolocation: "FR,US",
  otpEmail: "[email protected]"
});

Custom Messages

javascript
// Add instructions for recipients
const secret = await client.createSecret({
  content: "Monthly report data",
  expirationHours: 48,
  maximumViews: 10,
  description: "Q3 Financial Report",
  message: "Please review by Friday and provide feedback via email"
});

Builder Pattern

javascript
import { createSecretRequest } from 'sharokey-js';

const request = createSecretRequest()
  .setContent("Complex secret")
  .setDescription("Detailed description")
  .setMessage("Instructions for recipient")
  .setExpirationHours(24)
  .setMaximumViews(5)
  .setPassword("password")
  .setCaptcha(true)
  .setIpWhitelist("192.168.1.0/24,10.0.0.1")
  .setGeolocation("FR,US,CA")
  .setOtpEmail("[email protected]")
  .addAttachment('file1.txt', buffer1)
  .addAttachment('file2.pdf', buffer2);

const secret = await client.createSecret(request);

📊 Listing and Management

List All Secrets

javascript
const result = await client.listSecrets();
console.log(`${result.data.length} secrets found`);

result.data.forEach(secret => {
  console.log(`${secret.slug}: ${secret.description} (${secret.currentViews}/${secret.maximumViews})`);
});

List with Filters

javascript
const secrets = await client.listSecrets({
  status: 'active',
  creator: '[email protected]',
  limit: 10,
  search: 'keyword'
});

Secret Details

javascript
const secret = await client.getSecret('ABC123XY');

console.log('Description:', secret.description);
console.log('Message:', secret.message);
console.log('Creator:', secret.creator);
console.log('Remaining views:', secret.getRemainingViews());
console.log('Expires in:', secret.getTimeRemaining(), 'ms');
console.log('Active:', secret.isActive());
console.log('Has CAPTCHA:', secret.captcha);
console.log('OTP Type:', secret.otpType);
console.log('IP Whitelist:', secret.ipWhitelist);
console.log('Geolocation:', secret.geolocation);

Delete Secret

javascript
const deleted = await client.deleteSecret('ABC123XY');
if (deleted) {
  console.log('Secret deleted successfully');
}

Usage Statistics

javascript
const stats = await client.getStatistics();

console.log('Statistics:');
console.log('- Total secrets:', stats.totalSecrets);
console.log('- Active secrets:', stats.activeSecrets);
console.log('- Expired secrets:', stats.expiredSecrets);
console.log('- Total views:', stats.totalViews);
console.log('- Secrets with password:', stats.secretsWithPassword);
console.log('- Created today:', stats.secretsCreatedToday);
console.log('- Created this week:', stats.secretsCreatedThisWeek);
console.log('- Created this month:', stats.secretsCreatedThisMonth);

🔧 Advanced Features

javascript
const secrets = await client.searchSecrets("keyword", {
  limit: 20,
  status: 'active'
});

console.log(`${secrets.length} secrets found`);

Active Secrets Only

javascript
const activeSecrets = await client.getActiveSecrets(50);
console.log('Still accessible secrets:', activeSecrets.length);

Configuration Update

javascript
client.updateConfig({
  timeout: 60000,
  retries: 5,
  logLevel: 'debug'
});

// Chainable
client.updateConfig({ timeout: 30000 })
      .updateConfig({ retries: 3 });

📖 API Reference

SharokeyClient

Main Methods

  • createSecret(content, options?)Promise<Secret>
  • listSecrets(filters?)Promise<ListResponse<Secret>>
  • getSecret(slug)Promise<Secret>
  • deleteSecret(slug)Promise<boolean>
  • getStatistics()Promise<Statistics>

Utility Methods

  • generatePassword(length?, symbols?)string
  • testConnection()Promise<boolean>
  • validateToken()Promise<Object|null>
  • getCurrentUser()Object|null
  • getInfo()ClientInfo

Advanced Methods

  • createPasswordSecret(desc, options?)Promise<{secret, password}>
  • searchSecrets(query, options?)Promise<Secret[]>
  • getActiveSecrets(limit?)Promise<Secret[]>

Secret Request Methods

  • createSecretRequest(options?)Promise<SecretRequest>
  • listSecretRequests(filters?)Promise<ListResponse<SecretRequest>>
  • getSecretRequest(id)Promise<SecretRequest>
  • deleteSecretRequest(id)Promise<boolean>
  • getSecretRequestStatistics()Promise<Object>
  • getActiveSecretRequests(limit?)Promise<SecretRequest[]>

Secret

Properties

  • slug: string - Unique identifier
  • description: string - Description
  • creator: string - Creator email
  • maximumViews: number - Maximum views
  • currentViews: number - Current views
  • expiration: Date - Expiration date
  • hasAttachments: boolean - Has attachments
  • attachmentsCount: number - Number of attachments
  • shareUrl: string - Complete share URL

Methods

  • isActive()boolean
  • getRemainingViews()number
  • getTimeRemaining()number|null

Statistics

Properties

  • totalSecrets: number - Total secrets
  • activeSecrets: number - Active secrets
  • expiredSecrets: number - Expired secrets
  • totalViews: number - Total views
  • secretsWithPassword: number - Secrets with password protection
  • secretsCreatedToday: number - Created today
  • secretsCreatedThisWeek: number - Created this week
  • secretsCreatedThisMonth: number - Created this month

SecretRequest

Properties

  • id: number - Unique identifier
  • token: string - Request token
  • message: string - Message for recipient
  • description: string - Internal description
  • secretExpirationHours: number - Hours until secret expires
  • requestExpirationHours: number - Hours until request expires
  • maximumViews: number - Maximum views for secret
  • emailTo: string - Recipient email
  • emailReply: string - Reply-to email
  • creator: string - Creator email
  • status: string - Request status (active, expired)
  • url: string - Request share URL
  • createdAt: Date - Creation date

Methods

  • isActive()boolean
  • isExpired()boolean
  • getShareUrl()string

💡 Practical Examples

Web Application for Sharing

javascript
class SecretManager {
  constructor(token) {
    this.client = new SharokeyClient({ token });
  }

  async sharePassword(password, recipient) {
    const secret = await this.client.createSecret({
      content: password,
      description: `Password for ${recipient}`,
      expirationHours: 1,
      maximumViews: 1,
      otpEmail: recipient
    });

    return secret.shareUrl;
  }

  async shareDocument(filePath, description) {
    const fs = require('fs');
    const fileData = fs.readFileSync(filePath);

    const secret = await this.client.createSecret({
      content: "Confidential document attached",
      description: description,
      expirationHours: 48,
      maximumViews: 3,
      attachments: [{
        name: path.basename(filePath),
        data: fileData
      }]
    });

    return secret.shareUrl;
  }

  async requestCredentials(email, description) {
    const request = await this.client.createSecretRequest({
      message: "Please share the requested credentials securely",
      description: description,
      secretExpirationHours: 24,
      requestExpirationHours: 48,
      maximumViews: 1,
      emailTo: email,
      emailReply: "[email protected]"
    });

    return request.url;
  }

  async getDashboard() {
    const [stats, activeSecrets, activeRequests] = await Promise.all([
      this.client.getStatistics(),
      this.client.getActiveSecrets(10),
      this.client.getActiveSecretRequests(5)
    ]);

    return { stats, activeSecrets, activeRequests };
  }
}

Express.js Integration

javascript
const express = require('express');
const { SharokeyClient } = require('sharokey-js');

const app = express();
const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN
});

app.use(express.json());

// Create secret via REST API
app.post('/api/secrets', async (req, res) => {
  try {
    const { content, description, hours, views } = req.body;
    
    const secret = await client.createSecret({
      content,
      description,
      expirationHours: hours || 24,
      maximumViews: views || 1
    });

    res.json({
      success: true,
      shareUrl: secret.shareUrl,
      expiresAt: secret.expiration
    });
    
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// List secrets
app.get('/api/secrets', async (req, res) => {
  try {
    const result = await client.listSecrets({
      limit: parseInt(req.query.limit) || 50
    });

    res.json({
      success: true,
      secrets: result.data,
      pagination: result.meta
    });
    
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

app.listen(3000, () => {
  console.log('API started on http://localhost:3000');
});

React Hook Usage

javascript
import { useState, useEffect } from 'react';
import { SharokeyClient } from 'sharokey-js';

function useSharokey(token) {
  const [client] = useState(() => new SharokeyClient({ token }));
  const [secrets, setSecrets] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const createSecret = async (content, options) => {
    setLoading(true);
    try {
      const secret = await client.createSecret(content, options);
      setSecrets(prev => [secret, ...prev]);
      return secret;
    } catch (err) {
      setError(err.message);
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const refreshSecrets = async () => {
    setLoading(true);
    try {
      const result = await client.listSecrets();
      setSecrets(result.data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    refreshSecrets();
  }, []);

  return {
    secrets,
    loading,
    error,
    createSecret,
    refreshSecrets,
    client
  };
}

// Usage in a component
function SecretManager() {
  const { secrets, createSecret, loading } = useSharokey(process.env.REACT_APP_SHAROKEY_TOKEN);

  const handleCreate = async () => {
    await createSecret("My new secret", {
      expirationHours: 24,
      maximumViews: 1
    });
  };

  return (
    <div>
      <button onClick={handleCreate} disabled={loading}>
        Create Secret
      </button>
      
      <ul>
        {secrets.map(secret => (
          <li key={secret.slug}>
            {secret.description} - {secret.getRemainingViews()} views remaining
          </li>
        ))}
      </ul>
    </div>
  );
}

🚨 Error Handling

Error Types

javascript
import { ApiError } from 'sharokey-js';

try {
  await client.createSecret("test");
} catch (error) {
  if (error instanceof ApiError) {
    switch (error.status) {
      case 401:
        console.error('Invalid or expired token');
        break;
      case 403:
        console.error('Access denied');
        break;
      case 429:
        console.error('Rate limit reached');
        break;
      case 500:
        console.error('Server error:', error.message);
        break;
      default:
        console.error(`API error ${error.status}:`, error.message);
    }
  } else {
    console.error('Local error:', error.message);
  }
}

Local Validation

javascript
try {
  const secret = await client.createSecret({
    content: "", // Validation error
    expirationHours: -1 // Validation error
  });
} catch (error) {
  console.error('Validation error:', error.message);
  // "Validation errors: Content is required, Expiration hours must be between 1 and 1000"
}

Automatic Retry

javascript
// Network errors are automatically retried
const client = new SharokeyClient({
  token: 'test',
  retries: 5, // Maximum 5 attempts
  timeout: 60000 // 60 seconds
});

// 4xx errors are NOT retried (client errors)
// 5xx errors ARE retried (server errors)

🎛️ Advanced Configuration

Environment Variables

bash
# .env
SHAROKEY_TOKEN=sk_live_abcdefghijklmnop1234567890
SHAROKEY_API_URL=https://api.sharokey.com/api/v1
SHAROKEY_TIMEOUT=60000
SHAROKEY_LOG_LEVEL=info
javascript
const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN,
  apiUrl: process.env.SHAROKEY_API_URL,
  timeout: parseInt(process.env.SHAROKEY_TIMEOUT) || 30000,
  logLevel: process.env.SHAROKEY_LOG_LEVEL || 'info'
});

Environment-based Configuration

javascript
const configs = {
  development: {
    apiUrl: 'https://dev.api.sharokey.com/api/v1',
    logLevel: 'debug',
    validateSsl: false
  },
  staging: {
    apiUrl: 'https://staging.api.sharokey.com/api/v1',
    logLevel: 'info'
  },
  production: {
    apiUrl: 'https://api.sharokey.com/api/v1',
    logLevel: 'warn',
    retries: 5
  }
};

const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN,
  ...configs[process.env.NODE_ENV || 'development']
});

Custom Logging

javascript
// The library logs automatically based on configured level
// debug: Detailed requests
// info: Important operations
// warn: Non-critical problems  
// error: Critical errors

const client = new SharokeyClient({
  token: 'test',
  logLevel: 'debug' // See all HTTP requests
});

💬 Support

Technical Documentation

Resources

Contact

FAQ

Q: Does the library work in browsers?

A: Yes, it works in all modern browsers supporting the Web Crypto API (Chrome 37+, Firefox 34+, Safari 7+).

Q: Can I use enterprise tokens?

A: Yes, all Sharokey API token types are supported (user and enterprise).

Q: Are secrets really encrypted client-side?

A: Yes, AES-GCM-256 encryption is performed entirely client-side. The server only receives encrypted data.

Q: What's the maximum file size?

A: 10MB total for all files combined, 10 files maximum per secret.

Q: Does the library support TypeScript?

A: Yes, TypeScript definitions are included in the package.


Documentation generated 08/01/2025 - Sharokey Team

Released under the MIT License.