
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@fastslack/socialkit
Advanced tools
Open-source social media OAuth, token management, and publishing SDK. Connect accounts, auto-refresh tokens, publish content — all self-hosted.
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.
npm install @fastslack/socialkit
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" },
],
});
// 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: ... }]
// 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!" },
);
// 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();
// 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");
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: { /* ... */ },
});
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) { /* ... */ }
}
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 |
| 60 days | 1 day before | |
| 60 days | 1 day before | |
| 60 days | 1 day before | |
| Threads | 60 days | 1 day before |
// 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");
}
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
MIT
FAQs
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.