JARS DEMO · Hands-on workshop
gRPC & HTTPS
From Requests to Secure RPC.
Understand how HTTP, TLS, HTTP/2, and gRPC work together. Build a real service, secure the connection, and learn to diagnose the failures that matter.
14 chapters · about 3.75 hours · self-paced · runs entirely on your machine
REST in this workshop
- JSONself-describing text
- HTTP/1.1one request at a time per connection
- TLS 1.3port 8443 (8080 without TLS)
- TCP
gRPC in this workshop
- Protocol Buffersbinary, schema from .proto
- HTTP/2streams multiplexed on one connection
- TLS 1.3 · ALPN h2port 50051, mutual TLS on 50052
- TCP
Learning path
Observe it, break it, fix it
REST vs gRPC
One service, two front doors
| REST (FastAPI, HTTP/1.1) | gRPC (HTTP/2) | |
|---|---|---|
| Addressing | POST /v1/greetings | WorkshopService/SayHello |
| Payload | JSON text, readable without a schema | Protobuf binary, decoded with the .proto |
| Contract | Optional (OpenAPI, generated from code here) | Required (.proto, code generated from it) |
| Errors | HTTP status + JSON body (404, 422) | gRPC status in trailers (NOT_FOUND, INVALID_ARGUMENT) |
| Streaming | Not built in | Server, client and bidirectional |
| Browsers | Native | Needs gRPC-Web and a proxy |
| Debugging | curl, any browser | Generated clients, grpcurl with the .proto |
How it works
From handshake to RPC
TLS: the handshake and the trust decision
The client checks four things before sending a single request: the chain leads to a CA it trusts, the hostname is in the certificate’s SAN, the certificate is within its validity period, and the server holds the matching private key.
sequenceDiagram participant C as Client (trusts ca.crt) participant S as Server (server.crt + server.key) C->>S: ClientHello (SNI: localhost, ALPN: h2, key share) S-->>C: ServerHello (key share) - keys derived, rest encrypted S-->>C: Certificate server.crt, CertificateVerify (signed by server.key) Note over C: 1. chain: server.crt signed by ca.crt?<br/>2. hostname: "localhost" in SAN?<br/>3. validity: now within notBefore..notAfter?<br/>4. possession: signature valid? C->>S: Finished Note over C,S: application data (HTTP/1.1 or HTTP/2) flows encrypted
gRPC: a call over HTTP/2
A generated stub serializes the request; the channel sends it as an HTTP/2 stream whose path names the method; the server routes it to your servicer; the status comes back in the trailers.
flowchart TB
subgraph Client
A["grpc_client / your code"] --> B["generated stub<br/>WorkshopServiceStub"]
B --> C["channel<br/>(one reused HTTP/2 connection)"]
end
C -- "TLS 1.3 + ALPN h2" --> D
subgraph "grpc-server"
D["grpc.server<br/>HTTP/2 streams, max message size"] --> E["StatsInterceptor<br/>count + log method"]
E --> F["WorkshopServicer / AdminServicer<br/>routed by :path"]
F --> G["core (domain)"]
end
F -. "status in trailers<br/>grpc-status, grpc-message" .-> CCertificate lab
Your own CA, and every way trust can fail
ca.crt
JARS Workshop Local CA
CA:TRUE · trusted by every client and server
server.crt
grpc-server
SAN: localhost, grpc-server, rest-https
client.crt
workshop-client
clientAuth · authenticated, not admin
admin.crt
workshop-admin
clientAuth · authorized for AdminService
expired-server.crt
grpc-expired
valid Jan 1-31, 2024 only
rogue-ca.crt
Rogue Untrusted CA
nobody trusts it
rogue-client.crt
workshop-client
same name as client.crt - rejected
certs/scripts/certs.py with OpenSSL. Never committed, never baked into images, never to be trusted outside the workshop.uv run python certs/scripts/certs.py generate
uv run python certs/scripts/certs.py inspect server
uv run python certs/scripts/certs.py verify
uv run python certs/scripts/certs.py rotate server- Untrusted issuer
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate - Hostname not in SAN
Hostname Verification Check failed - Expired certificate
CERTIFICATE_VERIFY_FAILED: certificate has expired - No client certificate
PEER_DID_NOT_RETURN_A_CERTIFICATE (server log) - Authenticated, not authorized
PERMISSION_DENIED
Curriculum
14 chapters, about 3.75 hours
- 00Overview and SetupWhat you will build, what you need, and a running environment.10 min
- 01How HTTP WorksRequests, responses, methods, headers, status codes - read straight off the wire.15 min
- 02HTTPS and TLSEncryption in transit, certificates, and why a client trusts a server.20 min
- 03HTTP/2 FundamentalsBinary frames, streams, and many calls over one connection.15 min
- 04Protocol BuffersA typed contract, a compact encoding, and generated code.15 min
- 05Your First gRPC CallA unary RPC end to end: stub, channel, servicer, status.15 min
- 06REST vs gRPCThe same operation through both doors, and what is (and is not) comparable.10 min
- 07Streaming RPCsServer streaming, client streaming and bidirectional streaming - for real.20 min
- 08Enable TLSSecure the gRPC connection, then prove the bytes are no longer readable.15 min
- 09Certificate ValidationBreak each verification check on purpose, read the error, then issue and rotate certificates.20 min
- 10Mutual TLSThe client proves its identity too - and identity is still not permission.15 min
- 11Debugging ClinicA method for connection failures, and a reference of real errors with their causes.15 min
- 12Performance and DeadlinesMeasure honestly, find what really costs time, and choose deadlines on purpose.15 min
- 13Final ChallengeSix broken secure connections. Reproduce, diagnose, fix, verify - without weakening security.25 min
Get started
Prerequisites and local setup
| Tool | Version | For |
|---|---|---|
| Docker Desktop / Engine | Compose v2.20+ | runs the services and this site |
| uv | 0.5+ | Python 3.13, clients, examples, tests |
| OpenSSL | 1.1.1 or 3.x | certificates (or use the toolbox container) |
| Node.js | 22 | only to build the website yourself |
git clone https://github.com/jars-demo/grpc-demo.git
cd grpc-demo
uv sync
uv run python certs/scripts/certs.py generate
uv run python scripts/tasks.py up
uv run python scripts/smoke_test.pyThen your first REST, gRPC and mutual TLS calls:
uv run python examples/rest_client.py https://localhost:8443/v1/greetings --name Ada
uv run python -m grpc_client hello --name Ada
uv run python -m grpc_client --target localhost:50052 --cert certs/out/client.crt --key certs/out/client.key helloFinal challenge
Repair six broken secure connections
Scenario 01
The certificate nobody trusts
Scenario 02
Right server, wrong name
Scenario 03
The door that asks for ID
Scenario 04
Same name, wrong signature
Scenario 05
Authenticated is not authorized
Scenario 06
Impatient client
Open source
Contribute
MIT licensed, on GitHub.
Setup, checks, and how chapters are tested.
A command that did not work? Tell us.