CoAP Message IDs and Tokens: Use the Right Identity for Deduplication and Responses

Use the Message ID to correlate CoAP datagram acknowledgements and detect duplicate messages. Use the Token, together with the peer context, to associate a response with its request. Keeping these identities in separate state records prevents a retransmitted packet, a separate response, or a reused identifier from completing the wrong application operation.

The baseline is unicast CoAP over UDP in RFC 7252, with the secure Token-processing update in RFC 9175. This is an implementation qualification procedure, not a claim that a particular library has been tested. Observe, blockwise transfers, multicast, and reliable transports add their own rules and need separate fixtures.

1. Draw two identity domains

RFC 7252 sections 4.4–4.5 match acknowledgement/reset messages using the Message ID and endpoint, and define duplicate handling. Section 5.3 uses Tokens for request/response association. A piggybacked response must satisfy both matching rules; a separate response uses its own message exchange while retaining the request’s Token. See the CoAP correlation rules.

State record Identity and contents Lifetime question
Datagram exchange Peer context, direction, Message ID, message type, retransmission/deduplication state. Can a delayed duplicate still belong to this exchange?
Application request Peer context, Token, method/resource, result owner, and application status. Can a later response still refer to this request?
Product operation, if needed Application-defined operation identity and reconciliation state. Could a new protocol request repeat a previously executed action?

The third row is a product design responsibility. Neither a Message ID nor a Token automatically supplies persistent, exactly-once actuator semantics across reboot or a fresh request.

Two parallel CoAP UDP identity domains use peer plus Message ID for message handling and peer plus Token for request-response ownership.
Conceptual ownership map for unicast UDP. Empty ACKs have no Token bytes; separate responses retain the request Token in a new message exchange.

2. Make one trace show the distinction

Use an isolated test peer and a packet recorder. The following values are hypothetical labels, not recommended identifier-generation algorithms. Send a confirmable request with Message ID 0x4101 and Token A1. Its duplicate retransmission keeps that message identity. An empty acknowledgement has Message ID 0x4101, but no Token bytes. A later separate response can use Message ID 0x9001 with Token A1.

An empty acknowledgement to that confirmable response uses 0x9001. This short sequence demonstrates why looking up every incoming message in one “request ID” dictionary is unsafe. Empty messages and response messages need different interpretation before an application owner can be selected.

Record the wire fields and the internal lookup result side by side. If a logging wrapper prints one generic identifier, change the diagnostic representation so Message ID and Token are visibly different fields. Include a bounded endpoint/security-context label without logging keys or sensitive payloads.

3. Build a duplicate and reordering fixture

Fixture Expected application observation
Lose the acknowledgement, then deliver a duplicate confirmable request. The duplicate path is exercised without accidentally creating a second application execution in the selected policy.
Send two requests with distinct Tokens and return responses in reverse order. Each response reaches its own request owner.
Deliver a separate response with a new Message ID and the correct Token. The client associates it with the original request instead of rejecting it for Message ID mismatch.
Deliver a piggybacked response with the wrong Token. A matching Message ID alone cannot complete the request.
Reuse the same numeric Message ID from another peer. Peer context prevents cross-endpoint deduplication.
Deliver a late response after local request retirement. It cannot complete a newly allocated request that reused unsafe identity state.

Check both callback counts and the identity of the callback owner. A test that receives two valid payloads but attaches them to the wrong callers has failed. Preserve the ordered packet script so that each case can be repeated without relying on random network delay.

4. Review reuse at the correct layer

RFC 7252 prohibits Message ID reuse with the same endpoint within EXCHANGE_LIFETIME. It also specifies endpoint-aware matching. Those are protocol constraints, not a reason to guess that every local timeout has ended the message’s lifetime. See section 4.4.

Token reuse needs its own review. RFC 9175 section 4.2 strengthens client behavior when the security protocol does not itself bind requests and responses. It requires clients to avoid Token use that risks wrong association and recommends a sequence-based approach tied to a new or rekeyed secure connection. Follow the updated secure binding requirements through the actual library; do not replace them with an arbitrary short reuse delay.

Bound identity tables and define backpressure when no safe entry is available. Test wraparound and exhaustion using a reduced test namespace where appropriate, while retaining the production generation algorithm in a separate review. A local generation field can protect software callbacks, but it does not change fields on a received packet.

5. Verify the transport before copying the model

RFC 8323 removes the Type and Message ID fields for CoAP over TCP because the reliable transport supplies the corresponding message-delivery behavior. The Token still has a request/response role. Consequently, a UDP deduplication table is not a portable recipe for a TCP or WebSocket implementation. See the reliable-transport message model.

Record the selected transport and security mode in every test report. A library that offers one high-level API for several transports may expose different callback and lifetime behavior underneath it.

Hypothetical review finding

A diagnostic client stores pending reads by Message ID only. It works while the server returns piggybacked results. When a slower server begins using separate responses, valid results no longer match, and a later Message ID collision can misroute a callback. The revised design keeps exchange state and request state separate and passes the reverse-order and separate-response fixtures.

No target results are asserted here. Release evidence should include the two identity records, packet fixtures, reuse policy, and at-most-once callback checks. Authentication, resource authorization, and physical command completion remain separate product requirements.

Similar Posts