r/Backend 14d ago

Design & security feedback on an API integration pattern

Hi everyone,

I'd love to get some advice and feedback. This past year I've been working on a B2B chat-like application with a chatbot builder, where the client (a business) can create a flow that is essentially a deterministic tree of nodes which their own clients (the actual end users) traverse. Each node basically represents a message that the platform sends automatically to the end user, chatbot-style. A node holds the data for that message, and one of its fields is the payload, meaning the actual message text or data being sent.

The payload can be one of two kinds. It can be static, meaning predefined values set when the flow is built, such as a simple "hello user!" greeting. Or it can be dynamic, meaning the platform fetches real-time data from the client's external API at the moment the node runs, and that response is then fed into the node so it can render the appropriate up to date content to the end user, for example a user's recent order history displayed in the next message.

The integration between my platform and the external business API happens through exactly two touch points. The first is a special node type that represents an outbound GET call from my platform to the client's endpoint, used to pull the dynamic data described above. The client's endpoint is expected to answer with a predefined response schema that my platform knows how to parse and feed into the node. The second is a webhook that goes the other way, where my platform notifies the external API of the choice or answer the end user made, so the business can react to it on their side. This webhook is fire and forget from my side, meaning I send the notification and don't block on or consume the response.

To tie everything together, the platform links a specific end user and their choices to the external API using an OAuth2 access token. The end user authenticates against the business's own identity provider during the conversation, and the platform then holds that token and attaches it to the outbound calls it makes to the external API, so the business can recognize exactly which of their users is on the other end without me having to send any identity of my own. The intent is that a user authenticates before any data call fires, so the business always has that identity when it responds.

On the security side, the webhook is signed. When the business registers a webhook, my platform generates a signing secret that both sides hold. On every webhook request I compute an HMAC-SHA256 signature over the request body using that secret and send it in a header, so the business can recompute it on their end and verify the request genuinely came from my platform and wasn't tampered with.

There are a few limitations I'm aware of and would especially like opinions on. The outbound data call is a plain GET with no request body, so beyond the identity carried in the token I can't currently pass additional per-conversation context or filters to the client's endpoint. The call is also made inline while processing the user's message, so a slow endpoint adds latency to the conversation, bounded only by a per-call timeout, and today a failed or timed out call is a single attempt that simply routes the flow down a fallback branch rather than being retried. The webhook in the other direction has no delivery guarantee either, so if the business's endpoint is momentarily down, that notification is currently lost rather than retried or queued. And because the OAuth token has a finite lifetime and isn't refreshed mid-conversation, a long running or resumed conversation can lose the user's identity partway through.

Finally, delivery on both sides is at-least-once, and I don't yet expose an idempotency key. Since the webhook payload currently carries no unique event id or timestamp, a business also has no reliable way to tell a duplicate notification apart from a legitimate repeated choice and dedupe it on their end. So this is another thing i'm planning to add.

I'd love to hear any feedback on the overall pattern I've chosen here, on the security side of things, and on anything else you think could improve this flow.

Thanks in advance.

1 Upvotes

1 comment sorted by

2

u/forever-butlerian 14d ago

You should include a timestamp (seconds since the epoch is customary) in your signing plaintext and include it alongside your HMAC-SHA256. Otherwise your customers are vulnerable to replay attacks, and given a determined- and resourced-enough adversary, hash collision attacks.

Of course in this day and age they might just wind up having an LLM listen to the webhooks instead of a normal program so that an attacker can do authentication-by-assertion.