← MHD Andra Fahreza
--:-- UTC+7CV ↓
Case study · Identity & SSO · Government

Centralized SSO for a government agency

One identity, five apps, zero password sprawl.

ROLE
Sole architect & engineer
SECTOR
Identity & SSO · Government
STATUS
Live in production

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.

architecture diagram

Key technical decisions

Every one is a tradeoff. Here's what I chose and what it cost.

01

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.

02

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.

03

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.

04

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

OAuth2 + PKCELaravelIdentity sync

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.

Download CV ↓← See more work