Catching Up: Architecture, Security, and Concurrency in the Heka Auth Service
Hey everyone! First of all, I want to start with a huge apology for the radio silence over the last couple of weeks. My schedule has been absolutely packed, and between deep-diving into code and keeping up with project deliverables, I haven't had a spare moment to sit down and share my progress. But I’m back, and I have a lot of exciting engineering updates to talk about regarding my work on the Hiero (LF Decentralized Trust) Heka Identity Platform.
This past week has been incredibly productive. I’ve been heavily focused on two stacked PRs that introduce the GPG Contributor Verification Flow and the GitHub OAuth Binding. What started as building out new features quickly turned into an excellent exercise in software architecture, security hardening, and navigating CI pipelines.
Here’s a deep dive into what I’ve been building and the technical hurdles I overcame along the way.
1. Architectural Boundaries: Keeping Services Clean
One of the most important lessons this week was about strict separation of concerns. Initially, some of the logic and database wiring for the new GPG ownership challenge accidentally bled into the heka-identity-service.
Following some great code review feedback from my mentor, I spent time completely untangling this. I removed all the stray entities, DTOs, and manual migration snapshots from the identity service.
Now, the entire GitHub OAuth and GPG challenge flows live 100% exclusively inside the heka-auth-service. We also moved to a proper code-first approach for our database, generating clean MikroORM migrations directly within the auth service. This keeps our microservice boundaries strict—the identity service doesn't need to know how a contributor proved their identity; it just needs to trust the auth service.
2. Hardening Security: SSRF, Payloads, and Auth
When you are building a service that fetches public GPG keys from an external provider (like GitHub), you have to be paranoid about security.
During the review process, we identified and patched several potential attack vectors:
-
Preventing SSRF (Server-Side Request Forgery): Initially, the service took a GitHub username from the request and used it to construct a URL to fetch the GPG key. We locked this down by implementing a strict regex (
GITHUB_USERNAME_PATTERN) to validate the username format, ensuring malicious users couldn't inject path traversal characters (like../) into the outgoing API call. -
Trusting the JWT, not the Client: We refactored the challenge request endpoint to stop trusting user-supplied usernames entirely. Instead, the endpoint is now fully authenticated. It decodes the user's secure JWT token, extracts their
walletId, and looks up their verified GitHub binding in the database. -
Preventing Payload Abuse: Cryptographic endpoints are prime targets for denial-of-service via massive payloads. We clamped down on this by adding strict
@MaxLengthvalidations to the GPG signature DTOs. - Log Sanitization: We ensured that caller-controlled inputs (like the raw decrypted text of a signature) are never written to the application logs, preventing log injection attacks.
3. Concurrency: The "Burn-Before-Verify" Pattern
One of the most interesting challenges was handling race conditions. A GPG challenge relies on a one-time-use cryptographic nonce. But what happens if an attacker fires two identical verify requests at the exact same millisecond?
A simple if (challenge.consumed) check in the code isn't enough, because both requests might read the database before either has a chance to update it.
To solve this, I implemented an atomic burn-before-verify pattern using MikroORM's nativeUpdate. Before the service does any network I/O or cryptographic verification, it executes a targeted SQL update:
UPDATE gpg_challenges SET consumed = true WHERE id = ? AND consumed = false.
Because databases handle row-level locking natively, only one request will successfully update the row. The other will return 0 affected rows, allowing us to instantly block the replay attack. It’s a beautifully simple and bulletproof solution.
4. Wrestling with CI: Snyk and Transitive Dependencies
Finally, no week in open-source is complete without a CI pipeline mystery. Our security scanner (Snyk) suddenly started failing the build, throwing a low-severity vulnerability alert.
Finding the culprit was tricky because the vulnerability wasn't in code I wrote. It turned out to be a lockfile desync and a transitive dependency issue caused by express@5 pulling in an older, vulnerable version of body-parser (2.2.2).
Instead of doing a hacky lockfile resolution, I fixed it the clean way: explicitly declaring "body-parser": "^2.3.0" in our heka-auth-service/package.json. This naturally aligns with what Express wants while forcing the patched version, clearing the Snyk check entirely. I also had to make sure my Git history was perfectly clean and rebased, ensuring every single commit was signed off using the DCO (git commit -s) enforced by the LF Decentralized Trust.
Wrapping Up
This week was a fantastic reminder that building features is only 20% of the job. The other 80% is architecture, concurrency, security, and infrastructure. I'm incredibly proud of how robust the heka-auth-service is becoming.
Thank you all for sticking with me, and I promise the next update won't take as long!
Until next time,
Happy coding! 🚀
Top comments (0)