HBForge/Examples
23 · Integrations

Stytch — SMS OTP and magic links

Forward to Stytch's API. Or use forge/auth's MagicLink, TOTP, BackupCodes if you'd rather not depend on a vendor.

forge/serverNodeBunDenoCF Workers
Code
stytch-auth.js
const { WebApp } = require(class="tk-str">'@hyperbridge/forge/server');
const stytch    = require(class="tk-str">'stytch');
const client   = new stytch.Client({
  project_id: process.env.STYTCH_PROJECT_ID,
  secret:     process.env.STYTCH_SECRET,
});

const app = new WebApp();

app.post(class="tk-str">'/auth/sms', async (c) => {
  const { phone } = await c.req.json();
  await client.otps.sms.loginOrCreate({ phone_number: phone });
  return c.json({ sent: true });
});

app.post(class="tk-str">'/auth/verify', async (c) => {
  const { method_id, code } = await c.req.json();
  const r = await client.otps.authenticate({ method_id, code });
  return c.json({ session: r.session_token });
});

app.listen(3000);
How it works

Two endpoints: one to send the OTP, one to verify and return a session token. Stytch handles SMS delivery, rate limiting, and replay protection.

For an all-in-house variant, drop the Stytch dep and use forge/auth's MagicLink + forge/mail + TOTP.

WebApp's body cache makes the verify endpoint trivial — read the JSON once, no need to reconstruct streams.

Try it
Quickstart
curl -X POST http://localhost:3000/auth/sms -d '{"phone":"+15551234567"}'
Related modules