Skip to main content

v1.x to v2.0: HTTPTransportPreHook moved after authentication

In v1.x, HTTPTransportPreHook ran before the transport authenticated the request, so a plugin could put a credential on the request and have it authenticated. In v2.0 it runs after authentication, and a new HTTPTransportPreAuthHook occupies the earlier position.
If your plugin writes a credential - a virtual key, an Authorization header, an x-api-key - from HTTPTransportPreHook, that credential is now written after the point that authenticates it, and nothing errors either way. Where authentication rejects the request the hook never runs at all; where it permits the request the hook still runs and the header still reaches components downstream of it, so the plugin can appear to keep working on one deployment and stop on another. Move that work to HTTPTransportPreAuthHook.

Does this affect my plugin?

Two separate questions, and the answers differ. Does it need the new method to compile? Every Go implementation of schemas.HTTPTransportPlugin does, because HTTPTransportPreAuthHook is part of that interface. A plugin with nothing to do before authentication returns (nil, nil). Native .so plugins are the exception: the symbol is looked up optionally, so a plugin that never exports it keeps loading and is skipped by the phase. Does its behaviour need to move? Only if it touches credentials. A plugin that logs, rewrites a body, adds a tracing header, or short-circuits on a business rule stays exactly where it is - and gains something: HTTPTransportPreHook now sees the resolved caller identity on ctx, because authentication has already run.

Migration

Rename the function. The pre-auth phase receives the same *HTTPRequest - body included - and applies the same mutations, so nothing inside the hook has to change: Before (v1.x):
After (v2.0):
A plugin may export both hooks. They are independent phases. HTTPTransportPreAuthHook runs once per request; HTTPTransportPreHook runs once per request too, but only for requests that reach it — a pre-auth hook that short-circuits, or authentication rejecting the request, skips it.

What the pre-auth phase does not give you

Overview

Bifrost v1.4.x introduces a new plugin interface for HTTP transport layer interception. This guide helps you migrate existing plugins from the v1.3.x TransportInterceptor pattern to the v1.4.x HTTPTransportPreHook and HTTPTransportPostHook pattern.
If your plugin doesn’t use TransportInterceptor, no migration is needed. The PreLLMHook, PostLLMHook, Init, GetName, and Cleanup functions remain unchanged.

What Changed?

The HTTP transport interception mechanism changed from a simple function that receives and returns headers/body to a dual-hook pattern that works with both native .so plugins and WASM plugins.

Key Differences

Why the Change?

The new dual-hook pattern provides:
  1. WASM plugin support - Serializable types work across WASM boundary
  2. Response interception - Post-hook can modify responses before returning to client
  3. Simpler API - No middleware wrapper, direct function call
  4. Better testability - No fasthttp dependency in plugin tests
  5. Full context access - BifrostContext available for sharing data between hooks
  6. Custom response short-circuits - Return a full response to short-circuit

Migration Steps

Step 1: Update Imports

Remove the fasthttp import if present:

Step 2: Replace the Function

Before (v1.3.x):
After (v1.4.x+):

Step 3: Update Body Modification Logic

In v1.3.x, you received the body as a map[string]any. In v1.4.x, you work with req.Body bytes: Before (v1.3.x):
After (v1.4.x+):

Common Migration Patterns

Adding Headers

v1.3.x:
v1.4.x+:

Reading Headers

v1.3.x:
v1.4.x+:

Conditional Processing

v1.3.x:
v1.4.x+:

Error Handling / Short-Circuit

v1.3.x:
v1.4.x+:

Accessing Request Method and Path

v1.3.x:
v1.4.x+:

Testing Your Migration

  1. Build your updated plugin:
  2. Update Bifrost to v1.4.x:
  3. Test with a simple request:
  4. Verify logs show both hooks being called:

Troubleshooting

Plugin fails to load after migration

Error: plugin: symbol TransportInterceptor not found This error occurs if Bifrost v1.4.x is looking for the old function. Make sure:
  1. You’ve updated to HTTPTransportPreHook and HTTPTransportPostHook
  2. The function signatures match exactly:
    • func HTTPTransportPreHook(ctx *schemas.BifrostContext, req *schemas.HTTPRequest) (*schemas.HTTPResponse, error)
    • func HTTPTransportPostHook(ctx *schemas.BifrostContext, req *schemas.HTTPRequest, resp *schemas.HTTPResponse) error
  3. You’ve rebuilt the plugin with the correct core version

Body modification not working

Make sure you’re assigning back to req.Body in the pre-hook:

Response modification not working

Make sure you’re modifying resp in the post-hook:

Headers not being set

Make sure you’re modifying req.Headers or resp.Headers directly:

Context values not available in post-hook

Make sure you’re using the correct context key type:

Streaming Chunk Hook (v1.4.x)

Bifrost v1.4.x introduces a new hook for intercepting streaming response chunks:

HTTPTransportStreamChunkHook

This hook is called for each chunk during streaming responses, allowing plugins to modify or filter chunks before they’re sent to the client.
Key differences from HTTPTransportPostHook:
HTTPTransportPostHook is not called for streaming responses. Use HTTPTransportStreamChunkHook instead to intercept streaming data.

Migration for Existing Plugins

If your plugin implements HTTPTransportPostHook and you want to also handle streaming responses, add the new hook:

Need Help?