Let me guess how this goes. You build a login page. You wire up registration. You hash passwords, set up MFA, ship it, and move on to the features that actually make your product interesting. Then, three months later, someone from legal walks over (or pings you on Slack, because nobody walks anywhere anymore) and asks: "Can you show me an audit trail of every admin action on user accounts for the last 90 days?"
And you stare at your screen, because you don't have one.
I have been that developer. Most of us have. Identity governance sounds like something that belongs in a compliance PDF, not in your sprint backlog. But here is the thing: when a regulation says "immutable audit trail," a developer writes that code. When GDPR says "consent must be versioned, purpose-specific, and withdrawable," a developer designs the schema accordingly. When data residency rules say "EU user data stays in the EU," a developer builds that routing logic.
Governance is a development problem. And if you are building a user management system, the checklist below is what separates you from a very uncomfortable audit.
The Four Pillars (a.k.a. "The Stuff Nobody Budgets For")
Before we get to the checklist, here is the mental model. Identity governance breaks down into four pillars:
- Audit trails - A complete, immutable record of what happened to identity data, when it happened, who did it, and where they did it from.
- Consent records - A versioned history of what users agreed to, under which version of your privacy policy, and whether they later changed their mind.
- Data residency and sovereignty - Storing user data in the geographic regions that regulations require.
- Retention policies - Automated lifecycle rules so data does not live forever just because nobody wrote a cleanup job.
Each of these is the kind of work that gets estimated at "a couple days" and balloons into weeks. I know, because I have written those estimates and I have been wrong every time.
The Checklist
Print this out. Tape it next to your monitor. Or bookmark it. Whatever works.
Audit Logging
- All identity lifecycle events are logged. Every registration, login (success and failure), password change, MFA enrollment, profile update, role change, consent action, account suspension, deactivation, reactivation, deletion, data export request, and admin action generates an audit entry. If something happens to a user record, it is logged.
- Each log entry captures the full picture. That means: event type, timestamp (UTC, high precision), which user was affected, who performed the action (user, admin, or system process), source IP and user agent, success or failure, event-specific details, and a correlation ID to trace related events across services.
- Logs are immutable. Append-only. No updates, no deletes. If someone can edit your audit log, it is not an audit log. Use append-only database tables with constraints that prevent UPDATE and DELETE operations, or event-streaming platforms like Kafka that provide natural append-only semantics.
- Audit data lives separately from operational data. Your audit store should not be the same database your app reads from on every request. Separate storage prevents accidental deletion, keeps your operational queries fast, and lets you apply different retention windows.
- Logs are encrypted at rest and in transit. Audit logs contain IP addresses, user actions, and admin operations. Treat them like the sensitive data they are.
- You can answer compliance questions efficiently. "Show me all admin actions in the last 90 days." "Show me every event for user X in the last 24 hours." "Show me failed logins from this IP range." If you cannot run these queries without a full table scan, you have an indexing problem.
- You have a plan for GDPR anonymization. When a user exercises their right to erasure, you cannot just delete their audit entries (that destroys the trail). You anonymize PII by replacing user IDs, email addresses, and IP addresses with hashed or tombstone values. The event record survives; the personal data does not.
Consent Management
- Consent is not a single boolean. If your schema has a column called
accepted_termswith a true/false value, you have a problem. Consent is purpose-specific (marketing vs. analytics vs. third-party sharing), versioned against a specific privacy policy, time-bound, withdrawable, and provable. - Each consent decision is a separate, immutable record. When a user grants consent for marketing emails under privacy policy v2.3, that is one record. When they later withdraw it, that is a new record. You never update or delete the original. This gives you a complete history.
- Consent references a specific policy version. You need to track which version of your privacy policy was in effect when the user made their decision. When the policy changes, existing consent may need to be re-obtained.
- Users can withdraw consent through self-service. GDPR Article 7 requires that withdrawal be as easy as granting consent. If users consented with one click during registration, they should be able to withdraw with one click in their profile settings.
- Stale consent triggers re-prompting. When your privacy policy version changes, your system should detect that a user's consent was given under an older version and prompt them to review and re-consent. This can be a redirect on next login or an in-app banner. Until they re-consent, processing based on the stale consent should pause.
Data Residency
- You know which regulations apply to your users. GDPR does not strictly require storing data in the EU, but keeping EU data in EU data centers significantly simplifies compliance. India's DPDPA has localization provisions. China's PIPL has strict requirements. Russia requires citizen data stored domestically. Financial services, healthcare, and government sectors often layer on additional rules.
- User data routes to the correct regional store. When a user registers, their region is determined (from their address, phone number, IP address, or explicit selection), and their PII is routed to the appropriate regional database instance.
- Global metadata is separated from regional PII. Some data can live globally (user IDs, session tokens). Personal data lives regionally. This requires careful schema design up front, because retrofitting it later is painful.
- Cross-region admin access is auditable. If an administrator in one region queries user data in another region, that access is logged and governed.
Retention Policies
- Inactive accounts have an expiration policy. GDPR Article 5(1)(e) says personal data should be kept "no longer than is necessary." Accounts that have not logged in for a defined period (say, 24 months) get deactivated. After a further period (36 months), they get deleted. Users get a warning notification before either action.
- Expired session data is purged on schedule. Old session tokens and refresh tokens accumulate. A background job should clean them up on a defined cycle.
- Audit logs have a defined retention window. Financial services may require 7 years. Your organization may require less. Whatever it is, define it, automate it, and when the window expires, archive or delete the data.
- Retention enforcement is automated. Manual cleanup does not scale and will not happen consistently. A scheduled background job queries for data past its retention threshold, acts on it, and logs the action to the audit trail.
- You have reconciled conflicting retention requirements. Seven-year audit log retention and GDPR's right to erasure can coexist, but only if you anonymize PII in retained records. The audit trail stays intact; the personal data gets scrubbed.
Why This Is So Much Work (and What You Can Do About It)
If you have been counting, that is roughly 20 items on this checklist, and each one hides real engineering complexity. A production-quality audit log system alone can eat weeks of design, implementation, and hardening. Consent versioning with re-prompting logic is not trivial. Regional data routing requires infrastructure changes. Automated retention with anonymization needs careful testing to avoid destroying data you are legally required to keep.
This is infrastructure that every regulated application needs, but it is rarely budgeted for. Nobody puts "build consent management framework" on the product roadmap because it does not ship a feature users can see. It just prevents the kind of regulatory exposure that makes the news.
The point is not that governance is optional. It is not. The point is that building it from scratch, for every project, is wasted effort when the hard problems have already been solved. At Duende, we're working to provide developers with the tools they need to solve these challenges faster and with more confidence.
Start Here
Go through the checklist above. Be honest with yourself. For each unchecked item, ask: "Am I going to build this, or am I going to adopt something that already does it?" Both are valid answers. But "I'll get to it later" is not, because later is when the auditor shows up.
Governance is not glamorous work. But it is the work that keeps your application out of regulatory trouble, and your users' data handled with the care it deserves. And honestly, getting it right from the start feels a lot better than retrofitting it under pressure six months from now.
Your future self will thank you. Or at least, they will not curse you during an audit.
Thanks for stopping by!
We hope this post helped you on your identity and security journey. If you need a hand with implementation, our docs are always open. For everything else, come hang out with the team and other developers on GitHub.
If you want to get early access to new features and products while collaborating with experts in security and identity standards, join us in our Duende Product Insiders program. And if you prefer your tech content in video form, our YouTube channel is the place to be. Don't forget to like and subscribe!
Questions? Comments? Just want to say hi? Leave a comment below and let's start a conversation.