A Field Guide to CoAP — Part 1
Everything related to the Constrained Application Protocol I wish I knew when I started in IoT
My earliest foray into the world of IoT was back in 2010. I had an idea to create smart outlets that monitored power consumption and communicated over a low-power network. The only “slight” problem I faced was that I knew very little about networking, wireless, real-time embedded systems, protocols…okay, not exactly slight problems. The idea never got off the ground but it was that very project that started my career in IoT. My ambitions led me to study a bunch of relatively new IoT technologies and standards. I was particularly interested in low-power communication and the work being done by the company Sensinode (later acquired by Arm.) One technology they pioneered was CoAP and seemed perfect for my project.
Many developers may be unfamiliar with this flexible tool. You may have heard of or used protocols like HTTP or MQTT but awareness of CoAP seemed to be less common. I often get asked, “why should I used CoAP?” or, “explain why I shouldn’t use MQTT for x?” I’m uncertain why some protocols are more well-known than others but part of my goal with this post is to fix that.
Let me be clear: I strongly believe in, “choose the right tool for the job” and certain protocols (and radios and security models) are better suited for specific applications. I in no way make the claim that CoAP is better than anything else; rather I hope to share the design principles behind the protocol, what use cases it is optimized for, and how you as a developer can add CoAP as another tool in your problem solving toolbox.
What is CoAP
CoAP is short for the Constrained Application Protocol and known formally as RFC 7252. It is a transfer protocol developed by the IETF under the Constrained Resource Environments (CoRE) Working Group (they sure do love their quasi-PascalCase!) CoAP was designed with three goals in mind:
- Suitable for constrained environments
- Easy to understand
- Easy to implement
RFC 7228 defines “constrained” in more detail but the tl;dr includes:
- Limited memory, storage & compute (100s of KBs & 10s of MHz)
- Battery power
- Low bandwidth (Kbps — Kilo bits per seconds)
- Security, but specialized for, well, constrained devices
And as we’ll see, many features of CoAP are intentionally designed to satisfy these constraints.
Second, RFC 7252 is very readable as a short read at ~100 pages with diagrams. You can easily read it at least once over your lunch break and still have time to refill your coffee.
Note to those who are new to specifications: Anything around or less than 100 pages is considered extremely short. As a point of comparison the USB 2.0 spec clocks in at over 600 pages! Which makes sense, since USB is a very sophisticated protocol and as a result is not so easy to read.
The last goal of CoAP is that it is easy to implement. There are protocol implementations in just about every device-side and cloud-side programming language, with libcoap & californium being defacto reference implementations for devices and servers. But there are specific design features in the protocol that make it easy to implement in constrained environments, like how it uses UDP and a compact message format to save on payload size, but we’ll cover those details shortly.
CoAP Basics
CoAP is modeled after the request/response, client/server model of HTTP. This is in part what makes it so easy to grok for beginners. In fact, it supports the familiar GET, POST, PUT, DELETE verbs, which means it plays nicely when interoperating with actual HTTP, discussed in RFC 8075.
If you take away one thing from this post it is that you can consider CoAP a lighter version of HTTP designed for IoT.
Actually, let’s use RFC 8075 as a lesson in the extensibility of CoAP. I keep talking about CoAP as a single “thing” when in fact there are literally dozens of additional specifications based on RFC 7252 that enhance what you can do with CoAP. But most importantly these are all considered optional from a purist perspective. Here’s a diagram of what those are:
From here on out we’ll consider anything in RFC 7252 “basic”, a few common features from other specs “basic++” and everything else “advanced.” Don’t worry — we’ll get to the advance stuff soon enough.
Here are the most useful things I think you’ll need to know as a user of CoAP:
Messaging Model
CoAP follows a client/server messaging model just like the broader internet and HTTP. This makes it very easy to understand how to send messages to and from say a sensor and a database. But while we think of browsers as clients and cloud servers as, well, servers, in the world of CoAP anything can be a client, server or both. This can be really handy when designing an IoT system. For example, a single sensor node might be a client publishing readings to a cloud server while the cloud is a client watching the state of a device that went to sleep, acting as a server when it wakes up. It can even extend to the local network — two devices can communicate directly acting as client/server pairs.
Note about other protocols: Some protocols like MQTT are Publish/Subscribe (“pubsub”) instead of request/response. The difference between the two models is largely preference, though there are nuance technical differences to consider when choosing one model over the other. Don’t @ me!
CoAP is also asynchronous like other client/server models and leans into that due to the nature of IoT networks. Devices may go offline for planned and unplanned reasons and CoAP takes that into account with features like Tokens for matching requests and Message ID for caching & deduplication.
The last point to understand about CoAP’s messaging model is that every design decision is about efficiency. Efficiency includes the size of a message, how often a message is sent, but even deeply technical considerations like how much battery a message might use or the compute cost for a type of cryptography. A few examples of how CoAP tries to be efficient include:
- Defaulting to UDP to reduce the bandwidth overhead of a session
- Encoding fields as short codes to shrink size
- “Piggybacking” ack messages to cut down on handshakes
There are many more ways CoAP tries to be efficient, some that we’ll talk about in later sections, but most are laid out in the specification. Fortunately you don’t need to worry about those details unless you intend to implement the protocol from scratch.
Request/Response Semantics
CoAP shares many of the same semantics as HTTP, as we’ve said more than once, and they have many analogous features:
- URIs: CoAP endpoints can be addressed via URIs like HTTP/HTTPS but with the COAP/COAPS protocol and ports. They are
coaps://[URI]:5684
(secure) andcoap://[URI]:5683
(insecure) - Methods & Response Codes: The CoAP variants do what you think. GET, POST, PUT, DELETE are the main verbs, and 2xx-5xx are response codes
- Options: Similar to HTTP Headers but with lower overhead
- Content negotiation: Supports for different IANA content types, like JSON & XML
There are also aspects of CoAP’s semantics that are not like exactly like HTTP and are important to understand. Reliability is optional, unlike HTTP’s TCP-based strategy. This approach saves on message size and overall power usage. CoAP simply calls non-reliable messages “NON-confirmable.” Other message types include CONfirmable, ACKnowledge & ReSeT. Each is used as part of an efficient flow of piggybacking, reducing pings, caching, etc. IP Multicast, which isn’t generally used by HTTP, is a core primitive of CoAP since it is very useful for certain IoT applications. Think turning on all lights in a room (“scenes”) or keeping clocks in sync. Lastly, many of the components you might need in the cloud like routing, congestion control & DDoS mitigation are somewhat left up to the reader (and additional specifications.)
Security
We’d be remiss if we didn’t discuss security — after all, the “S” in IoT stands for Security (just a joke!) Earlier we said secure CoAP URIs have a default protocol of coaps://
and port of 5684. So how is security implemented? Recall that CoAP by default uses UDP so it chose DTLS (TLS for Datagrams) to secure the transport layer. With DTLS as a basis, CoAP defines four security modes:
- Pre-shared keys (PSK) This is the simplest mode to implement since keys are defined ahead of time but also the least scalable solution. Also, generating, distributing and protecting PSKs can be error-prone. That said, for simple deployments this is the most common approach I’ve seen.
- Raw Public Key (RPK) This mode uses asymmetric key pairs without the complexity of a certificate. RPKs are generally lend themselves to a better end to end security architecture (ex. key derivation from public keys) and work well with modern Public Key Infrastructure.
- Certificates Certs are what one would consider “enterprise-grade security.” Like RPK this mode uses asymmetric key pairs but with X.509 certificates, and a mature ecosystem of certificate lifecycle management (roots of trust, cert rotation, etc.) Implementing certificate-based security with CoAP usually comes with specialized solutions (+specs) and deserves a separate post to do it justice.
- No Security Technically not a security mode, and unfortunately the most common mode in the wild. Often this is due to relying on higher-level security like VPNs but is generally driven by cost-cutting, laziness or developer ignorance.
There are several security considerations discussed in RFC 7252. One that has made CoAP famous recently was an attack using cellular devices to DDoS the network. This category of attack is known as an Amplification attack and all UDP-based protocols are susceptible. The sad thing is that this attack is largely mitigated with even the most basic form of security and a decent cloud implementation.
Security is a big topic and fortunately there’s a lot of great work happening in this space. We’ll be digging more into security later on in the series.
Getting Started with CoAP
The easiest way to get started with CoAP is right from your terminal. Among the implementations I recommend:
- libcoap (C/C++)
- Californium (Java)
- go-coap (Go)
- aiocoap (Python)
- node-coap (Node.js)
I’m lean towards Go these days so here’s a quick client/server example from go-coap:
A great place to get help is Stack Overflow, Reddit, CoRE mailing list or use the Issue list from a specific library.
In Summary
Let’s take a look again at that mindmap, but this time hide everything we didn’t call “basic”:
That looks a lot less scary! And that’s the point :) CoAP as a basic protocol is simple and easy to understand. With just this post you should be equipped to use CoAP as a basic building block for your next project or product. But there’s much more for us to discuss!
Remember the one thing you weren’t supposed to forget? Consider CoAP a lighter version of HTTP designed for IoT!
Coming next
I originally planned this CoAP discussion as a single post…and do we have a lot more to talk about. I expect at least three more posts to come next:
- Part 2: beyond the basics
- Part 3: advanced use cases
- Part 4: CoAP security in detail
However, I’d love feedback on this article and what you’d like to see covered! Leave a comment below or message me on Twitter/LinkedIn.
Cheers!