Auth Middleware

Let's add execution authentication with one middleware file. It rejects route-execution requests that don't carry a valid bearer token, and it passes the verified user id to every tool call in that run:

import { allow, defineMiddleware, reject } from "@b4run/sdk"
 
export default defineMiddleware(async (req) => {
  const auth = req.headers["authorization"]
  if (!auth?.startsWith("Bearer ")) {
    return reject(401, { error: "Missing bearer token" })
  }
 
  const token = auth.slice("Bearer ".length)
  const userId = await verifyJwt(token).catch(() => null)
  if (!userId) {
    return reject(401, { error: "Invalid token" })
  }
 
  return allow({ userId })
})
 
async function verifyJwt(token: string): Promise<string> {
  // Replace with your real verifier.
  const res = await fetch("https://auth.example.com/verify", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ token }),
  })
  if (!res.ok) throw new Error("verify failed")
  const body = (await res.json()) as { readonly sub: string }
  return body.sub
}

NotesCopy link to section: Notes

  • The tool name is the file name. The file is tools/loadProfile.ts, so you call ctx.tools.loadProfile(...). A file named tools/load-profile.ts would be ctx.tools["load-profile"](...), so stick with camelCase file names.
  • There's one global middleware. src/middleware.ts runs once per route-execution request, before the route. For per-route policy, branch on req.routeId.
  • reject short-circuits. The route never runs, and the body of reject(status, body?) becomes the HTTP response.
  • allow(context) flows to tools. Whatever you pass becomes ctx.middleware on every tool call for that request. Call allow() with no arguments and it's undefined.
  • Throwing returns 500. Any uncaught error becomes HTTP 500. Return an explicit reject(401, ...) with a real body so callers get a useful response.
  • Check where you deploy. This middleware runs under b4 dev, the Node B4.run HTTP runtime (b4 start or the generated server.mjs), and Hono builds. The generated LangSmith graph entries leave B4.run's HTTP middleware out, so on LangSmith you'll enforce authentication in the platform itself.