Centralized SSO for a government agency
One identity, five apps, zero password sprawl.
CONTEXT
A government agency ran several internal applications — HR, attendance, correspondence, and e-signature — each built at a different time, each with its own login screen and user table. Staff memorized a different password per app, and offboarding someone meant hunting through every system to make sure their access was actually gone.
THE PROBLEM
Give every internal app one trusted identity — so a person logs in once, access is granted and revoked in one place, and no app stores its own passwords — without rewriting the apps that already exist.
CONSTRAINTS
- Existing apps integrate, not migrate — no rewrites allowed.
- Public-sector security expectations — no implicit flow, no secrets in the browser.
- The HR system is the source of truth for who works here — identity must stay in sync.
- Runs on the agency's own infrastructure — no external identity provider.
- Offboarding must revoke access everywhere the moment HR marks a leaver.
WHAT I DESIGNED
A central Laravel identity provider speaking OAuth2 Authorization Code with PKCE. Each existing app becomes an OAuth client: it redirects to the IdP to authenticate and receives scoped tokens back — no app ever handles a password again. A scheduled sync pulls the workforce from the HR system of record, so joiners and leavers propagate automatically.
Key technical decisions
Every one is a tradeoff. Here's what I chose and what it cost.
Authorization Code + PKCE — not implicit or password grant
Authorization Code with PKCE keeps credentials at the IdP alone; each app integrates a redirect flow via a small reusable client package.
Tradeoff: The password grant would let each app keep its familiar login form, but it means every app touches credentials — the exact sprawl we are removing.
HR system as the source of truth, synced on a schedule
I made the HR system authoritative with a scheduled reconciliation, always resolving conflicts in HR's favor.
Tradeoff: Sync latency is measured in minutes rather than instant — the price of a single source of truth over hand-managed identities that drift.
A single point of trust — with its failure mode planned
I accepted centralization for its security and instant-revocation benefits, backed by short-lived tokens plus refresh, health checks, and a recovery runbook.
Tradeoff: One IdP is also one thing that, if it goes down, locks everyone out — so the outage is bounded and understood, not catastrophic.
Scoped tokens per app, not one all-access session
I issued scoped tokens so each app receives only the access it needs.
Tradeoff: More scope design up front, in exchange for a far smaller blast radius if any one app is breached.
Outcome
5+ apps sit behind one login, access is granted and revoked from one console, no client app stores passwords, and joiner/leaver changes sync automatically from HR.
STACK
Have a system that needs building — or fixing?
Tell me the problem and the constraints. I'll tell you honestly whether I'm the right person and how I'd approach it.