Skip to content

Open-source social media OAuth, token management, and publishing SDK for Node.js

License

Notifications You must be signed in to change notification settings

fastslack/socialkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@fastslack/socialkit

Open-source social media OAuth, token management, publishing, and credit system SDK for Node.js.

Connect user accounts, auto-refresh tokens, publish content, and manage usage credits — all self-hosted with zero third-party dependency.

Features

  • OAuth flows for 7 platforms: LinkedIn, Twitter/X, Instagram, Facebook, TikTok, Threads, YouTube
  • AES-256-GCM encrypted token storage
  • Automatic token refresh with configurable background scheduler
  • Publish content with text, images, and video
  • Credit/quota management — define operations, costs, packages, and track usage
  • Storage adapters — in-memory (dev) or Prisma (production), or bring your own
  • Zero dependencies — only Node.js built-ins + optional Prisma peer dependency
  • MIT licensed — genuinely free software

Install

npm install @fastslack/socialkit

Quick Start

import { SocialKit, MemoryTokenStore, MemoryCreditStore } from "@fastslack/socialkit";

const kit = new SocialKit({
  tokenStore: new MemoryTokenStore(),
  creditStore: new MemoryCreditStore(),
  encryptionKey: SocialKit.generateKey(),
  providers: {
    linkedin: {
      clientId: process.env.LINKEDIN_CLIENT_ID!,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
      callbackUrl: "https://myapp.com/api/social/linkedin/callback",
    },
    twitter: {
      clientId: process.env.TWITTER_CLIENT_ID!,
      clientSecret: process.env.TWITTER_CLIENT_SECRET!,
      callbackUrl: "https://myapp.com/api/social/twitter/callback",
    },
  },
  operations: [
    { id: "publish:linkedin", name: "Publish to LinkedIn", cost: 1 },
    { id: "publish:twitter", name: "Publish to Twitter", cost: 1 },
    { id: "generate:thread", name: "Generate thread", cost: 3 },
  ],
  packages: [
    { id: "starter", name: "Starter", credits: 50, price: 19, currency: "USD" },
    { id: "pro", name: "Pro", credits: 200, price: 49, currency: "USD" },
  ],
});

OAuth Flow

// 1. Generate auth URL and redirect user
const url = kit.getAuthUrl("linkedin", { userId: "user_123" });
// → redirect user to `url`

// 2. Handle callback (exchange code for tokens, store encrypted)
await kit.handleCallback("linkedin", {
  code: req.query.code,
  userId: "user_123",
});

// 3. Check connected accounts
const connections = await kit.getConnections("user_123");
// → [{ provider: "linkedin", status: "active", expiresAt: ... }]

Publishing

// Publish to one platform
const result = await kit.publish("linkedin", "user_123", {
  text: "Hello from SocialKit!",
});
// → { success: true, postId: "...", postUrl: "https://linkedin.com/..." }

// Publish to multiple platforms
const results = await kit.publishAll(
  ["linkedin", "twitter", "facebook"],
  "user_123",
  { text: "Cross-posted with SocialKit!" },
);

Token Management

// Get a valid token (auto-refreshes if expiring)
const token = await kit.getToken("user_123", "linkedin");

// Disconnect a platform
await kit.disconnect("user_123", "linkedin");

// Start background token refresh (every 15 min)
kit.startRefreshScheduler();

// Manual refresh cycle
await kit.refreshNow();

Credit System

// Add credits
await kit.credits.addCredits("user_123", 100, "purchase", "Starter pack");

// Check balance
const balance = await kit.credits.getBalance("user_123");
// → { balance: 100, totalPurchased: 100, totalUsed: 0 }

// Check if user can afford operations
const canAfford = await kit.credits.canAfford("user_123", [
  "publish:linkedin",
  "publish:twitter",
]);

// Deduct credits
await kit.credits.deductOne("user_123", "publish:linkedin");

// Bulk deduction
await kit.credits.deduct("user_123", [
  "publish:linkedin",
  "publish:twitter",
  "generate:thread",
]);

// Get transaction history
const history = await kit.credits.getTransactions("user_123");

Prisma Adapter (Production)

npm install @prisma/client

Add the models from node_modules/@fastslack/socialkit/prisma/schema.prisma to your schema, then:

import { SocialKit } from "@fastslack/socialkit";
import { PrismaTokenStore, PrismaCreditStore } from "@fastslack/socialkit/prisma";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const kit = new SocialKit({
  tokenStore: new PrismaTokenStore(prisma),
  creditStore: new PrismaCreditStore(prisma),
  encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!,
  providers: { /* ... */ },
});

Custom Storage Adapter

Implement the TokenStore and/or CreditStore interfaces:

import type { TokenStore, CreditStore } from "@fastslack/socialkit";

class MyTokenStore implements TokenStore {
  async save(token) { /* ... */ }
  async get(userId, provider) { /* ... */ }
  async getAll(userId) { /* ... */ }
  async getExpiring(bufferMs, maxFailures) { /* ... */ }
  async update(userId, provider, data) { /* ... */ }
  async delete(userId, provider) { /* ... */ }
}

Token Refresh Schedule

Each platform has different token lifetimes. The refresh scheduler handles them all:

Platform Access Token TTL Refresh Buffer
Twitter/X 2 hours 30 min before
YouTube 1 hour 10 min before
TikTok 24 hours 2 hours before
LinkedIn 60 days 1 day before
Instagram 60 days 1 day before
Facebook 60 days 1 day before
Threads 60 days 1 day before

Next.js Integration Example

// app/api/social/[provider]/route.ts
import { kit } from "@/lib/socialkit";
import { getServerSession } from "next-auth";

export async function GET(
  req: Request,
  { params }: { params: { provider: string } },
) {
  const session = await getServerSession();
  const url = kit.getAuthUrl(params.provider, {
    userId: session.user.id,
  });
  return Response.redirect(url);
}

// app/api/social/[provider]/callback/route.ts
export async function GET(
  req: Request,
  { params }: { params: { provider: string } },
) {
  const session = await getServerSession();
  const { searchParams } = new URL(req.url);

  await kit.handleCallback(params.provider, {
    code: searchParams.get("code")!,
    userId: session.user.id,
  });

  return Response.redirect("/dashboard/connections");
}

Generate Encryption Key

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

License

MIT

About

Open-source social media OAuth, token management, and publishing SDK for Node.js

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published