
Product
Microsoft Teams Notifications Are Now Available in Socket
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.
@opensyber/tokenforge
Advanced tools
Device-bound session security — W3C DBSC + ECDSA P-256 signatures + AitM detection. Drop-in for Auth0 / Okta / Clerk / Entra ID.
Device-bound session security for the post-AiTM era. W3C DBSC–aligned, ECDSA P-256 + WebAuthn, drop-in for Auth0 / Okta / Clerk / Microsoft Entra ID. Every request after login is cryptographically signed with a device key that never leaves the browser. A stolen cookie without the device key is useless.
<script
src="https://tokenforge-api.opensyber.cloud/sdk.js"
data-api-key="tf_your_api_key"
></script>
The script auto-generates ECDSA P-256 device keys (non-extractable, IndexedDB-stored), binds the session, and signs every fetch() request with X-TF-Signature, X-TF-Nonce, X-TF-Timestamp headers. On Chrome 146+ Windows it transparently uses the browser's native DBSC; on other browsers it polyfills via Web Crypto.
npm install @opensyber/tokenforge
// Express
import { tokenForgeMiddleware } from '@opensyber/tokenforge/express';
app.use(tokenForgeMiddleware({ apiKey: process.env.TOKENFORGE_API_KEY! }));
// req.tf.bound, req.tf.trustScore, req.tf.deviceId
// Next.js (App Router)
import { withTokenForge } from '@opensyber/tokenforge/nextjs';
export const GET = withTokenForge(handler, { apiKey: process.env.TOKENFORGE_API_KEY! });
// Fastify
import { tokenForgePlugin } from '@opensyber/tokenforge/fastify';
fastify.register(tokenForgePlugin, { apiKey: process.env.TOKENFORGE_API_KEY! });
// Hono
import { tokenForgeMiddleware } from '@opensyber/tokenforge/hono';
app.use('/api/*', tokenForgeMiddleware({ apiKey: env.TOKENFORGE_API_KEY }));
Sign up at tokenforge.opensyber.cloud — free tier: 1,000 verifications/month, no credit card.
This release graduates the protocol surface from beta. Subsequent 1.x is backward-compatible additions only.
Aligned with the W3C draft + Chrome 146 native rollout:
POST /v1/dbsc/challenge — issue one-shot challenge (register/refresh/step_up)
POST /v1/dbsc/register — bind device with JWS-signed challenge response
POST /v1/dbsc/refresh — rotate bound cookie, run risk policy
POST /v1/dbsc/sessions/:id/revoke — admin soft-revoke
GET /.well-known/tokenforge/jwks — public verifier keys (5-min edge cache)
GET /.well-known/tokenforge/dbsc — service descriptor for SDK auto-discovery
Five OIDC IdPs + SAML 2.0:
import { exchangeSso } from '@opensyber/tokenforge/server/internal';
// After Okta / Entra / Google Workspace / Auth0 / generic OIDC login
const result = await exchangeSso(db, store, {
tenantId, workforceAppId,
idToken: req.body.idToken, // from your IdP
jwks, // cached via getJwks()
});
// result: { ok: true, subjectId, externalSubject, email, challenge, challengeExpiresAt }
JWKS cache: 24-hour freshness with stale-fallback when IdP is unreachable. xmlsoap claim namespace for Microsoft AD FS / Azure AD compatibility built in.
import { requireFreshSig } from '@opensyber/tokenforge/server';
app.use('/admin/*', requireFreshSig({ minTrustScore: 90 }));
app.use('/billing/*', requireFreshSig({
minTrustScore: 95,
requireWebAuthn: true,
}));
Per-tenant policy via tf_tenants.step_up_actions JSON:
[
{ "path": "/admin/billing", "requireFreshSig": true, "freshSigMaxAgeSec": 30 },
{ "path": "/admin/*", "requireFreshSig": true, "requireWebAuthn": true }
]
Exact match wins over glob. Glob /admin/* matches /admin/users but not /admin (no segment past prefix).
// Client
const sig = await tokenforge.signAction({
action: 'transfer',
body: { fromAccount, toAccount, amount },
});
fetch('/api/transfer', {
method: 'POST',
headers: { 'X-TF-Action-Signature': sig },
body: JSON.stringify({ fromAccount, toAccount, amount }),
});
5-second freshness window. JWS claims include actionHash (SHA-256 over canonicalized body) so an attacker can't replay the signature with a different transfer amount.
12 events, HMAC-SHA256 signed, retried with [1s, 4s, 15s] backoff, stable X-TF-Delivery-Id across retries:
session.bound session.verified session.revoked
trust_score.degraded trust_score.critical session.hijack_attempt
usage.cap_exceeded dbsc.risk_signal dbsc.policy_block
dbsc.session_step_up dbsc.session_revoked webhook.test
import { verifyWebhookSignature } from '@opensyber/tokenforge/webhooks';
app.post('/webhooks/tokenforge', async (c) => {
const rawBody = await c.req.text();
const ok = await verifyWebhookSignature({
body: rawBody,
signatureHeader: c.req.header('X-TF-Signature') ?? '',
timestampHeader: c.req.header('X-TF-Timestamp') ?? '',
secret: c.env.TOKENFORGE_WEBHOOK_SECRET,
});
if (!ok) return c.json({ error: 'bad_signature' }, 401);
// handle event ...
});
Secret rotation grace window: 24 hours. Send the new secret while the old one stays valid; receivers verify against either.
Browser TokenForge API Your Server
│ │ │
│ 1. Generate ECDSA P-256 │ │
│ keypair (non-extractable) │ │
│ │ │
│ 2. POST /v1/dbsc/challenge ───>│ │
│ <─────── { challenge } ────────│ │
│ │ │
│ 3. POST /v1/dbsc/register ────>│ Store public key │
│ + JWS over challenge │ │
│ <─── { sessionId, deviceId } ──│ │
│ │ │
│ 4. fetch('/api/data') │ │
│ + X-TF-Signature ──────────────────────────────────────> │
│ │ │
│ │ <── POST /v1/edge/verify ── │
│ │ Verify signature │
│ │ Run AitM heuristics │
│ │ Compute trust score │
│ │ ──> { allow, score: 92 } │
│ <──────────────────────────────────── 200 OK ─────────────── │
The device key never leaves the client. The TokenForge service holds the public key + session metadata. Your server passes request context, gets back an allow/step_up/block decision.
| Signal | Weight | Detects |
|---|---|---|
| Signature | 30 | Tampering, missing/wrong device key |
| IP Address | 15 | IP change since binding |
| Geo Location | 15 | Country mismatch |
| Fingerprint | 15 | Browser/device fingerprint drift |
| Velocity | 10 | Multiple IPs in short window |
| Timing | 10 | Clock skew beyond ±60s |
| Nonce | 5 | Replay attacks |
Score >= 80: allow. Score 40-79: step_up. Score < 40: block. Thresholds configurable per tenant.
TokenForge runs after authentication — bring your own IdP:
| IdP | Integration | Built-in support |
|---|---|---|
| Microsoft Entra ID | Custom Authentication Extension webhook | Roadmap M11 (Q3 2026) |
| Auth0 | Auth0 Action snippet | Roadmap M14 — Marketplace listing pending review |
| Okta | Inline Hook + Custom Authenticator | Roadmap M15 — OIN listing pending review |
| Clerk | @tokenforge/clerk-middleware shim | Roadmap M16 |
| Auth.js / NextAuth | Works today via @opensyber/tokenforge/nextjs | ✅ |
| Firebase Auth | Works today via @opensyber/tokenforge/express | ✅ |
| Supabase Auth | Works today via @opensyber/tokenforge/express | ✅ |
| Custom JWT | Works today | ✅ |
import { TokenForgeProvider, useTokenForge } from '@opensyber/tokenforge/react';
function App() {
return (
<TokenForgeProvider config={{
apiBase: '/api',
getSessionId: () => getSession(),
}}>
<YourApp />
</TokenForgeProvider>
);
}
function ProtectedPage() {
const { bound, trustScore, deviceId } = useTokenForge();
if (!bound) return <BindButton />;
return <Dashboard trustScore={trustScore} deviceId={deviceId} />;
}
The server adapters work against your own database / KV — no hosted service required:
import { createTokenForgeRoutes } from '@opensyber/tokenforge/server';
import { D1Storage } from '@opensyber/tokenforge/server/storage';
// or PostgresStorage, RedisStorage, or implement the StorageInterface
const tf = createTokenForgeRoutes({
storage: new D1Storage(env.DB),
sessionMaxAge: 86400,
});
app.route('/api/tf', tf);
Storage backends shipped: D1 (Cloudflare Workers), PostgreSQL, Redis. Bring your own via StorageInterface.
| Platform | Status |
|---|---|
| Chrome 146+ Windows | ✅ Native DBSC + polyfill fallback |
| Chrome 146+ macOS / Linux | ⏳ DBSC pending Google rollout; polyfill works today |
| Safari (macOS / iOS) | ✅ Polyfill via Web Crypto + IndexedDB |
| Firefox | ✅ Polyfill |
| Edge 146+ | ✅ Inherits Chromium DBSC |
| Node.js 18+ (server) | ✅ |
| Bun, Deno | ✅ |
| Cloudflare Workers | ✅ |
| Plan | Price | Verifications/mo |
|---|---|---|
| Free | $0 | 1,000 |
| Pro | $49/mo | 50,000 |
| Team | $199/mo | 250,000 |
| Enterprise | Custom | Unlimited + SLA |
The SDK code in this repository is MIT-licensed and runs against any storage backend — you can self-host without a TokenForge subscription.
Security issues: security@opensyber.cloud (PGP key available). Coordinated disclosure within 90 days; CVE assignment for confirmed vulnerabilities.
SDK: MIT (see LICENSE.md). Hosted service requires API key — governed by TokenForge Terms.
FAQs
Device-bound session security — W3C DBSC + ECDSA P-256 signatures + AitM detection. Drop-in for Auth0 / Okta / Clerk / Entra ID.
We found that @opensyber/tokenforge demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.

Security News
Socket CTO Ahmad Nassri joins AppSec leaders at Black Hat to discuss active malware, package manager risks, and software supply chain defense.