Skip to main content

Command Palette

Search for a command to run...

Lessons Learned & Practical Advice for Developers from my implemented Web App

Real-world insights from integrating an external IdP into a legacy PHP ecosystem—and what developers should know before building their own auth system

Updated
6 min read
Lessons Learned & Practical Advice for Developers from my implemented Web App
N
Senior-level Fullstack Web Developer with 10+ years experience, including 2 years of Team Lead position. Specializing in responsive design and full-stack web development across the Vue.js and .NET ecosystems. Skilled in Azure/AWS cloud infrastructure, focused on DevOps techniques such as CI/CD. Experienced in system design, especially with software architecture patterns such as microservices, BFF (backend-for-frontend). Hands-on with Agile practices in team leading, and AI-assisted coding.

Series: Web Authentication Demystified — From Concepts to Real-World
ARC 2 — APPLYING THE THEORY: MY REAL IMPLEMENTATION
Previous: Security Analysis of my implemented Web App Authentication System

After exploring authentication from fundamentals to architecture to deep dive and security analysis, we’ve reached the final chapter of this series—a reflection on what actually happens when theory meets reality. Building a production authentication system that integrates a government IdP, a legacy-friendly PHP framework, Redis sessions, and CloudFront might look straightforward on paper, but real-world constraints introduce nuance that textbooks rarely address.

This article captures the lessons learned from implementing the CSL authentication system, what went smoothly, what proved unexpectedly tricky, and the practical guidance I’d give to teams attempting similar integrations. And finally, if I had the chance to redesign the system today, what I would refine or modernize.

Disclaimer

The articles in this current arc are based on a real authentication system I integrated and implemented for a government education department. Due to the Non-Disclosure Agreement (NDA) between myself and the client, certain internal details, configurations, and architectural specifics have been intentionally generalized or omitted. All explanations focus on the conceptual and technical patterns rather than sensitive operational information. I’ve made every effort to describe the system as accurately as possible while fully respecting confidentiality and security requirements.


1. Why Real Systems Rarely Match Textbook Examples

In documentation and academic diagrams, OAuth2 and OIDC look clean, predictable, and linear.
Reality, however, brings:

  • legacy frameworks

  • existing permission systems

  • organizational boundaries

  • CDN requirements

  • evolving IdP capabilities

  • security policies

  • infrastructure constraints

Most systems don’t get to start from scratch. They must absorb authentication, not reinvent it.

In CSL’s case:

  • HumHub/Yii uses server-managed PHP sessions

  • Government IdP dictates the authentication process

  • CloudFront must enforce access to protected assets

  • The application requires its own user model and permissions

  • The system must work across many browsers and devices

  • No tokens may be exposed to the frontend

This is why the final architecture became a hybrid design rather than a “pure OIDC” implementation. Real systems adapt patterns to context, not the other way around.


2. What Went Well

✔ External IdP Integration

Delegating authentication to the government IdP brought immediate benefits:

  • No password management in the app

  • Built-in MFA

  • Strong identity proofing

  • Standard OAuth2/OIDC flows

Identity assurance became someone else’s well-maintained responsibility.

✔ Redis Session Strategy

Redis-backed PHP sessions were:

  • fast

  • scalable

  • easy to invalidate

  • perfectly aligned with HumHub

This gave the app centralized control over login state without token exposure.

✔ User Provisioning Model

The user_auth mapping table worked smoothly:

  • stable matching via IdP sub claims

  • graceful handling of first-time users

  • clear boundary between IdP identity and application identity

✔ CloudFront Secured via Signed Cookies

Protecting static assets through short-lived CloudFront cookies delivered strong security with minimal complexity.

✔ Hybrid Flow Simplicity

The combination of:

  • OIDC identity

  • backend-only tokens

  • PHP session
    resulted in a clean and secure integration with minimal risk of token leakage.


3. What Was Tricky

Session Handling Across Redirects

OIDC depends on short-lived browser redirects, but PHP sessions weren’t designed with OAuth2’s back-and-forth dance in mind. Ensuring session integrity during state and code exchange required careful orchestration.

User Provisioning Edge Cases

Mapping IdP identities to internal users uncovered corner cases:

  • disabled accounts

  • incomplete profile data

  • reassigning identities

  • teachers moving departments

These are the kinds of scenarios that specs never mention but real organizations always have.

AWS signed cookie generation isn’t complex, but coordinating:

  • policy creation

  • key rotation

  • expiration windows

  • integration with app login
    took thoughtful design to avoid fragile behavior.

No Tokens in the Browser

This improved security but required:

  • backend-only flow

  • no ID tokens for frontend rendering

  • careful handling of redirects and session regeneration

A “simple design decision” cascades into dozens of implementation details.


4. Advice for Teams Integrating an External IdP Into Legacy or Session-Based Systems

Start with identity mapping

Before technical implementation, answer:

How will an external identity link to an internal user?

Define the mapping early, whether via:

  • sub

  • email

  • employee ID

  • or custom claims

Treat the IdP as the source of identity, not authorization

Let the IdP authenticate the user.
Let your app decide what they’re allowed to do.

Avoid exposing tokens to the frontend unless absolutely necessary

Legacy systems were never designed for browser-held JWTs.
A backend-only flow avoids:

  • XSS token theft

  • debugging complexity

  • refresh token storage issues

Don’t force a “textbook” OIDC implementation onto a legacy environment

Frameworks like PHP/Yii were built for stateful sessions.
Use that strength instead of fighting against it.

Prioritize secure cookies

Make them:

  • HttpOnly

  • Secure

  • SameSite=Lax/Strict

This single decision prevents entire classes of vulnerabilities.

Use the IdP for authentication, but retain permission control locally

Organizations evolve faster than identity claims do.

Log everything

Successful logins, failures, provisioning, CloudFront cookie issuance—log it.
Audit trails are invaluable for debugging and compliance.


5. If I Were to Redesign It Today

The system is robust, secure, and appropriate for its context—but there are modern refinements worth considering:

PKCE for completeness

Even though server-side apps don’t require PKCE, some modern IdPs enforce or recommend it.

Use ID tokens more extensively

Currently the access token is the main validated artefact.
Adopting ID tokens can standardize claim parsing and add nonce verification.

Refresh token rotation (for backend → IdP communication)

Would improve security for long-lived backend tasks.

Structured audit logging

A modern audit service (e.g., OpenSearch, CloudWatch, Elasticsearch index) would make operations smoother.

mTLS between CSL and IdP (if supported)

Provides strong service authentication in regulated environments.

CloudFront key rotation automation

To streamline signed cookie lifecycle management.

Each change is evolutionary, not revolutionary—the core architecture is sound.


Final Thoughts

If this series demonstrates anything, it’s that real-world authentication systems are a mosaic of constraints, protocols, legacy decisions, and modern security practices. The CSL system didn’t follow a perfect textbook blueprint; it followed the realities of PHP architecture, government IdP requirements, CDN constraints, and operational needs. And despite that, or perhaps because of it, the final implementation is stable, secure, and maintainable.

Thank you for following this journey—from core concepts, to tokens, to OAuth and OIDC, to flow design, hybrid architecture, and now the closing lessons. If this series helps even one developer approach identity integration with more clarity and confidence, it’s already a success.

With the core series complete, we can shift from concepts and architecture into hands-on, practical deep dives. For those who want to explore the implementation details behind the system, the optional bonus articles will walk through topics like building an OIDC callback in PHP/Yii/HumHub, understanding CloudFront signed cookies, designing Redis-backed session storage, and comparing OAuth2, OIDC, and SAML in real scenarios. If you’re ready to go deeper into the mechanics behind the ideas, the next articles are for you.

Implementing an OIDC Callback in PHP/Yii/HumHub (with code examples)

CloudFront Signed Cookies — How They Work and Why We Used Them

Redis as a Session Store for Scalable Web Architecture

Comparing OAuth2, OIDC, and SAML with real examples

Web Authentication Demystified — From Concepts to Real-World

Part 5 of 14

This series breaks down modern web authentication, from core concepts like OAuth, OIDC, and tokens to real implementation details. You’ll learn how the pieces fit together and see how a production-ready system is built and secured.

Up next

Security Analysis of my implemented Web App Authentication System

A detailed look at the security mechanisms behind the authentication flow—how threats are mitigated, tokens are validated, and sessions are protected