We have written twice about why a company with a couple of dozen internal systems needs a single identity layer: once on the identity debt that builds up quietly in engineering organisations, and once on what 24 separate passwords mean as 24 separate attack surfaces. In August we added a third piece arguing that, once passkeys arrive, enrollment becomes the new attack surface and almost all of the fix lives in the identity provider.
This post is about the product underneath those arguments. simpliSSO is the identity portal Simplico builds and hands over: an Authentik identity provider federated with your Microsoft 365 / Azure AD tenant, sitting in front of every internal application. Below is what is actually in the box, how the twelve modules fit together, what the custom code does, and — just as important — what is scoped per engagement or explicitly outside the scope.
1. The shape of the problem simpliSSO is scoped against
The reference deployment on the product page is a real-world shape, not a toy: 24 services, 3 protocols, 12 feature modules, 10 weeks to go-live. Those 24 services are not 24 modern web apps. They are a mix that most mid-size manufacturers and distributors in the region will recognise:
- modern internal web tools (A/R aging, warehouse reports, document control, IT services, approvals, projects reporting)
- a legacy ERP — Infor M3 — that speaks SAML2, but with non-standard attribute names
- communication tools — WhatsApp Business and a 3CX IP phone system — that have no concept of "SSO" at all
- hardware — Kyocera printers, label printers, a warehouse robot system — that can only authenticate over LDAP or not at all
A product that only handled the first group would cover maybe half the estate and leave the riskiest half untouched. simpliSSO is designed around the whole mix.
2. Three protocols, three tiers, one identity provider
The architecture is a single hub. Azure AD remains the source of truth for who your staff are; Authentik is the one place that decides what they can reach and issues the tokens; every application connects to Authentik through whichever protocol it can actually speak.
flowchart TD
STAFF["Staff"] --> PORTAL["App portal tile launcher"]
PORTAL --> AK["Authentik identity provider"]
AK --> AAD["Microsoft 365 and Azure AD"]
AAD --> AK
AK --> POL["Policies and step up MFA"]
AK --> OIDC["OIDC provider"]
AK --> SAML["SAML2 provider"]
AK --> LDAP["LDAP outpost"]
OIDC --> MAP["Property mappings add ERP role claims"]
MAP --> T1["Tier 1 web apps"]
SAML --> T1
LDAP --> T3["Tier 3 printers and legacy hardware"]
PORTAL --> T2["Tier 2 WhatsApp and 3CX via account linking"]
Tier 1 — web apps over OIDC and SAML2. Modern apps use OpenID Connect and receive a signed JWT. Legacy ERPs use SAML2. Authentik runs both providers side by side, so a modern A/R tool and a fifteen-year-old ERP log in through the same front door.
Tier 2 — communications via account linking. WhatsApp and 3CX cannot consume an OIDC token. Instead, custom linking stages bind each person’s WhatsApp number and 3CX extension to their Azure AD identity on first login, and the portal tiles deep-link to the right conversation or a pre-authenticated phone client.
Tier 3 — hardware over LDAP. Printers, label hardware and other boxes that cannot speak OIDC or SAML2 authenticate against an LDAP outpost that Authentik deploys. Robot systems that cannot even do that are reached by portal deep link only.
Azure AD is the default upstream, but it is not a hard dependency. Authentik federates with Google Workspace, Okta, generic OIDC and SAML2 providers, and — importantly for air-gapped or strictly on-premise sites — directly with an existing on-prem Active Directory or OpenLDAP directory, with no cloud round trip. Sources can be stacked in one flow, for example Microsoft 365 for staff and LDAP for contractors.
3. The twelve modules
Every module is scoped and priced independently. Three are mandatory; the rest can be phased or dropped before signing, with a proportional price adjustment.
| Module | What it delivers | Status in a standard engagement |
|---|---|---|
| F-01 MS365 / Azure AD federation | Azure as upstream IdP; MFA and Conditional Access pass through | Mandatory |
| F-02 Authentik install and hardening | Docker Compose production stack with PostgreSQL, Redis, Nginx TLS, backups, admin portal, branding | Mandatory |
| F-03 Application configuration | Every service registered as an OIDC or SAML2 application, group-based access policies, Blueprint YAML config-as-code | Mandatory |
| F-05 JWT claims for ERP roles | Company code, division and ERP roles embedded in the token | Phaseable |
| F-06 Step-up MFA policy | Extra MFA challenge on designated sensitive systems | Phaseable |
| F-07 App portal tile launcher | FastAPI endpoint that shows each user only the apps they are authorised for, with Thai/English labels | Phaseable |
| F-08 WhatsApp account linking | Links each staff member’s WhatsApp number to their directory account | Phaseable |
| F-09 3CX extension linking | Maps extensions to accounts; tile opens a pre-authenticated web client | Phaseable |
| F-10 Infor M3 SAML2 workaround | Bridges Authentik’s SAML2 output to M3’s non-standard attributes and NameID | Phaseable |
| F-11 Thai language UI | Localised login, MFA prompts, errors and password reset, with branding | Phaseable |
| F-12 Testing, QA and UAT | End-to-end testing across every service, including token expiry, MFA failures and SAML mismatches | Included |
| F-13 Documentation and handover | Architecture diagrams, admin runbook, on/offboarding guides in Thai and English, live handover session | Included |
Two things about this table are worth calling out. First, the mandatory baseline is genuinely small — federation, a hardened install, and the application registrations. A company that only needs "one login for our web apps" can stop there. Second, most of the phaseable modules exist because real estates contain at least one system that does not behave: an ERP with odd SAML attributes, a phone system with no SSO concept, a workforce that needs Thai on the login screen.
4. The custom Python layer — and why it stays yours
The part of simpliSSO that is not off-the-shelf Authentik is a thin layer of Python that runs inside Authentik as expression policies, property mappings and Django stages. There are no external services to operate, and all of that Python becomes the client’s IP on final payment.
Claim shaping (F-05). Property mappings put ERP context — the M3 company, division and roles, an A/R access level — directly into the token. The application reads the role from the token instead of maintaining its own permission table. That is the difference between "SSO for logging in" and "SSO for authorisation": when someone changes department in Azure AD, their ERP role changes everywhere on the next login, not when someone remembers to update a second system.
Step-up MFA (F-06). An expression policy of roughly twenty lines checks whether the target application is on a sensitive list and whether the last MFA verification is older than 30 minutes; if both are true, Authentik challenges again before issuing a token with elevated claims. Most daily traffic never sees it. The finance and IT-admin systems always do.
The M3 workaround (F-10). Infor M3 expects attribute names and a NameID format that do not match a standards-clean SAML2 assertion. Rather than patching the ERP, custom mappings translate on the identity provider side. This is the kind of module that only exists because someone has already lost a week to it.
The tile launcher (F-07). A FastAPI endpoint renders the portal: only the applications the signed-in user is authorised for, with icons, Thai/English labels and deep links. It is the first screen staff see, and it is generated from the same group policies that gate access — so the portal can never show an app the policy would refuse.
5. What integrating one more app actually costs
The integration contract for a new application is four environment variables:
OIDC_CLIENT_ID = "your-app-client-id"
OIDC_CLIENT_SECRET = "your-app-client-secret"
SESSION_SECRET = "random-256-bit-string"
OIDC_ISSUER_URL = "https://sso.example.com/application/o/<app-slug>/"
Each Authentik OIDC provider publishes a discovery document at .well-known/openid-configuration, so the app fetches endpoints, signing keys and supported scopes — including the custom ERP claims — from one URL. The product page carries working examples for FastAPI, Django, Express and PHP; in each case the app redirects to Authentik, handles the callback, and reads groups and roles from the token. No home-grown authentication code, and no per-app password table to forget about during offboarding.
6. Delivery: ten weeks, paid against working milestones
The rollout is phased so that the foundation is proven before any custom work starts:
flowchart TD
W1["Weeks 1 to 2 infrastructure F01 F02"] --> W3["Weeks 3 to 4 core SSO F03"]
W3 --> W5["Week 5 ERP claims step up MFA M3 workaround"]
W5 --> W6["Week 6 Thai UI and branding"]
W6 --> W7["Weeks 7 to 8 portal WhatsApp and 3CX linking"]
W7 --> W9["Weeks 9 to 10 testing UAT handover"]
Payment is tied to verified deliverables, not dates: 30% at signing, 40% when Microsoft 365 federation is live with the first five apps connected, and the final 30% when every service is live and UAT is signed off. After go-live there is an optional month-to-month support retainer in three tiers (next business day, 4 business hours, or 2 business hours response), cancellable on 30 days’ written notice.
7. Shipped, per engagement, and out of scope
Identity is an area where overclaiming does real damage, so here is the line drawn plainly.
Shipped as listed modules: Azure AD federation with MFA pass-through, a hardened self-hosted Authentik stack, OIDC and SAML2 application registration, LDAP outpost for hardware, SCIM provisioning and deprovisioning from Azure AD with session invalidation, group-based access policies, ERP claim mapping, step-up MFA, the portal tile launcher, WhatsApp and 3CX linking, the M3 SAML2 bridge, Thai UI, testing, and bilingual documentation.
Configured per engagement, not a separate module: passkey and WebAuthn enrollment policy. Authentik supports building a dedicated enrollment flow with its own stages and policies, and the hardening steps from our passkey enrollment post — gating enrollment behind step-up, restricting recovery paths, alerting on credential changes for privileged roles — are applied as part of the policy work for clients who want them. They are not a pre-packaged feature with its own line item. The same applies to connecting identity events into a SIEM such as simpliSOC: the logs exist; wiring them into alerting is scoped work.
Out of scope: the hardware itself. Printers, label systems and robots are client-provided; simpliSSO includes portal deep links to them where technically possible, but does not replace or reconfigure their firmware.
8. Who it fits
simpliSSO fits organisations that already run Microsoft 365 (or another standards-compliant directory), have somewhere between ten and a few dozen internal systems, and have at least one legacy system that a pure SaaS SSO product would leave behind. It fits particularly well where the operations team needs to own and run the stack on its own infrastructure afterwards — Docker Compose on a 4 vCPU / 8 GB host, with configuration kept as versioned Blueprint YAML rather than in someone’s memory.
It is a poor fit if you have five SaaS tools and no on-premise systems; a hosted identity service will be simpler.
FAQ
Does simpliSSO replace Azure AD?
No. Azure AD stays the authoritative directory and keeps handling passwords, MFA and Conditional Access. Authentik never stores staff passwords; it federates upstream to Azure AD and issues tokens downstream to every application.
Can we run it without Microsoft 365?
Yes. Authentik federates with Google Workspace, Okta, generic OIDC or SAML2 providers, or directly with an on-premise Active Directory or OpenLDAP directory for sites that cannot depend on a cloud directory.
What happens to access when someone leaves?
IT deactivates the account once in Azure AD. SCIM pushes the change to Authentik, active sessions are invalidated, and every connected application stops accepting that identity. If passkeys or other authenticators are in use, removing registered credentials as part of offboarding should be part of the policy configuration — a deactivated account with a live authenticator is a reactivation risk.
Are passkeys included?
Passkey enrollment hardening is configured per engagement as part of the policy work, not shipped as a separate module. See the shipped versus per-engagement section above.
Who owns the custom code?
All custom Python — policies, mappings and stages — becomes your IP on final payment.
How is it priced?
Per deployment, quoted as a fixed price after a scoping call. Mandatory modules are F-01, F-02 and F-03; everything else can be added, phased or removed before signing.
If you are counting logins across your own estate and the number is uncomfortable, tell us how many apps, which protocols, and which upstream directory you use, and we will scope a fixed-price proposal in a single call: hello@simplico.net, phone (+66) 97 496 6397, WhatsApp (+66) 83 001 0222, or LINE iiitum1984. The full architecture and integration examples are on the simpliSSO product page.
Sources:
- simpliSSO — Simplico
- Passkey Enrollment Is Your New Attack Surface — Simplico
- Your Staff Have 24 Passwords. Your Business Has 24 Attack Surfaces. — Simplico
- The Security Risk Sitting Quietly in Your Engineering Org — Simplico
Latest Posts
- Can an LLM Predict a Flood? What AI Actually Does in Flood Forecasting, and Where Drones and Gauge Cameras Fit September 27, 2026
- Running Flood Response Like a SOC: A Detection-and-Response Blueprint for Thailand’s Water Crises September 26, 2026
- From Whiteboard to Dashboard: Vehicle Load Planning Meets Live GPS Tracking September 22, 2026
- From Paper to Pipeline: Digitizing Multi-Factory Precast Slab Production, Warehouse, and Delivery September 20, 2026
- What Simplico Builds: A Product Portfolio Overview and What Each One Actually Gets You September 12, 2026
- Inside simpliMES: How One Django Core Runs Discrete and Batch Manufacturing on the Same Engine September 7, 2026