Plugins

Magic link

Official plugin — request and verify a one-time email link to sign in under /auth.

magicLink() issues a hashed, single-use token (default 10 minutes). Request sends the link via Channel (auth-magic-link); verify exchanges it for a hybrid session and creates the user on first success.

The one rule

Enable gate.auth, then .plug(magicLink()). Tokens are hashed at rest — never log the raw link. Delivery goes through fx.send; use exposeDevToken only for local DX without SMTP.

Quick start

Plug it

src/app.ts
import { oke } from "okengine";
import { magicLink } from "okengine/plugins";

export const app = oke({
  name: "shop",
  env: "dev",
  gate: { auth: {} },
}).plug(magicLink({ baseUrl: "http://127.0.0.1:6530" }));
const { data } = await api.auth.requestMagicLink({ email: "ali@example.com" });
// data.ok === true; Channel delivers auth-magic-link
// data.devToken only when exposeDevToken

POST /auth/magic-link/request. Under oke test the console driver captures mail; with oke dev, Mailpit receives the real SMTP message.

Verify

const { data } = await api.auth.verifyMagicLink({ token });
// session tokens + userId

POST /auth/magic-link/verify. Bad or reused tokens → AuthFailed / invalid_credentials.

Pre-account hijack defense

Completing verify proves inbox ownership. An unverified email+password account parked on that address is reclaimed (sessions revoked, hashes cleared, emailVerified set). Verified owners re-auth only — no credential purge.

Options

OptionTypeDefaultMeaning
secretstringactive*HMAC secret (*from gate.auth)
sessionsSessionStoreactive*Session store
ttlMsnumber10mChallenge lifetime
baseUrlstringOKE_APP_URL or :6530Origin used to build the magic link
fromstringOKE <no-reply@oke.local>Template From address
exposeDevTokenbooleanfalseInclude raw token in the request response
identitiesIdentityStorenewEmail → user map
verificationsVerificationStorenewChallenge store

Surfaces

FlowPathGate
auth.requestMagicLinkPOST /auth/magic-link/requestgate.public + otp rate
auth.verifyMagicLinkPOST /auth/magic-link/verifygate.public + otp rate

Consequence: the plugin contributes the auth-magic-link Channel template and EN/AR catalog bodies ({{link}}, {{token}}). Override copy by merging your own catalog at boot.

Delivery drivers

drivers.channel.emailDelivery
consoleDev inbox (local/test default)
smtpAny SMTP host — Mailpit under oke dev (dev default)
resend / sndrHosted email APIs
taqnyat-mailTaqnyat Mail API (additive option)

Taqnyat Mail

oke.config.ts
export default {
  drivers: {
    channel: {
      email: { dev: "smtp", test: "console", prod: "taqnyat-mail" },
    },
  },
};
EnvMeaning
TAQNYAT_MAIL_TOKENTaqnyat bearer token enabled for Email
TAQNYAT_CAMPAIGNCampaign name required by Taqnyat mailSend.php

The plugin needs no change — delivery stays Channel-mediated via fx.send. SMTP/Mailpit remains the default docker path; taqnyat-mail is strictly additive.

Live tests (opt-in)

The Taqnyat live suite sends real email and burns real quota, so it is double-gated: it runs only when OKE_EMAIL_LIVE=1 and the real credentials (TAQNYAT_MAIL_TOKEN, TAQNYAT_CAMPAIGN, plus OKE_TEST_TAQNYAT_MAIL) are all present.

Credentials alone never send; without the flag the suite skips visibly — never a silent pass.

OKE_EMAIL_LIVE=1 TAQNYAT_MAIL_TOKEN= TAQNYAT_CAMPAIGN=auth \
  OKE_TEST_TAQNYAT_MAIL=you@example.com bun test src/plugins

Troubleshooting

Learn more

  • OTP — numeric code instead of a link
  • Gategate.auth
  • Channelfx.send, Mailpit, consents

Next

On this page