Interactive Auth
An OTP auth layer over devframe's node-side primitives (exchangeTempAuthCode / verifyAuthToken / revokeAuthToken), so a host needn't re-implement the protocol.
An OTP auth layer over devframe's node-side primitives (exchangeTempAuthCode / verifyAuthToken / revokeAuthToken), so a host needn't re-implement the protocol.
Adapters gate with this layer by default via createDevServer(def) / initDevframe / initHub (auth: true). Use createInteractiveAuth only for a custom transport:
import { createContextRpcServer } from 'devframe/internal'
import { createInteractiveAuth } from 'devframe/recipes/interactive-auth'
import { attachWsRpcTransport } from 'devframe/rpc/transports/ws-server'
const auth = createInteractiveAuth(ctx, {
clientAuthTokens: process.env.CI ? [process.env.DEVFRAME_CI_TOKEN!] : undefined,
})
const { rpcGroup, onConnected, onDisconnected } = createContextRpcServer({ context: ctx, auth })
attachWsRpcTransport(rpcGroup, { server, onConnected, onDisconnected })
auth.printBanner()As auth it wires rpcFunctions, authorize, and onConnect — see Security.
createInteractiveAuth(context, options?)
| Option | Default | Purpose |
|---|---|---|
clientAuthTokens | undefined | Pre-shared bearer tokens, always trusted. |
banner | a small boxed console message | Called with { code, url }; prints via printBanner(). |
serverUrl | context.host.resolveOrigin() | Magic-link base URL. |
Returns a DevframeAuthHandler:
| Field | Purpose |
|---|---|
rpcFunctions | anonymous:devframe:auth + anonymous:devframe:auth:exchange (handshake), devframe:auth:revoke (self-revoke). |
authorize(methodName, session) | Resolver gate: allows anonymous: methods, else requires session.meta.isTrusted. |
onConnect(peer, session) | Connect-time trust from a bearer on the WS upgrade URL (?devframe_auth_token=). |
printBanner() | Prints the code + magic-link URL. |
Using the pieces directly
Without createContextRpcServer, wire the pieces directly:
const auth = createInteractiveAuth(ctx)
auth.rpcFunctions.forEach(fn => ctx.rpc.register(fn))
auth.printBanner()
// in your resolver:
if (!auth.authorize(methodName, session))
throw new Error('not authorized')
// on each new WS peer:
auth.onConnect(peer, session)Auth storage is internal, not devframe/node/hub-internals.