A shared identity service with configurable login steps and protocol connections.
This identity and access management case study covers a service whose sign-in sequence can be configured. Administrators arrange the stages a user moves through. A user proves who they are, enters credentials and passes a verification step before giving consent. Policies decide which steps a given user meets.
Browser applications and supported legacy clients reach that shared process through the protocols each one speaks. We set out to keep the decisions reusable and inspectable. That matters most when a login turns up facts it did not have at the start.
The challenge
A flow may need to identify the user before it can decide which second factor to ask for. A plan fixed ahead of that point would run on incomplete data.
The policy also has to mean the same thing across every connected application. Administrators need to see why a stage ran or was skipped, without reading a separate authentication path for each protocol.
What we built
A configurable flow can combine several factors. It can ask for a password and verify an email address. It can also send an invitation or request consent, then add a time-based code or a WebAuthn key.
Applications connect through the protocol each one speaks. The service supports OpenID Connect and OAuth2 for modern web clients. It also speaks SAML and LDAP for directory and enterprise sign-on, with proxy authentication or RADIUS for older clients. Gateways handle the proxy and legacy interfaces.
An inspection view shows the decisions a flow made as it moved through the stages. Audit events record identity activity, and object permissions control administrative access. YAML blueprints describe the flows, policies and applications, so a setup can be reviewed and rebuilt later.
Technical approach
The planner reads the policies attached to a flow and to its stages. A plan can be cached for reuse. Even so, the service checks the chosen policy bindings again during the run, using data that only became available by then. Entry prerequisites tell signed-in, signed-out and administrator-only access apart.
Each stage works through a challenge-and-response API. The client asks for a challenge and sends back its answer, so browser clients and supported legacy clients can share one executor.
For authorization codes, the service validates the registered return address, the protocol parameters and the allowed scopes. No one-time code is issued until the authentication and application-access checks pass. PKCE adds one more check here. It confirms that the challenge and the verifier match. It rejects a verifier that arrives with no original challenge on record.
A refused account still gets the same password-hash work as a real one, which limits timing differences between them. Expression policies raise a separate concern, because they run Python. Permission to edit them is a server-level duty, as is the trust placed in policy editors, protocol gateways and deployment credentials.
Project success
Administrators can change the conditional login stages and inspect the decisions a flow made. Connected applications rely on the shared authentication sequence. A blueprint file keeps a reviewable record of the setup. The client gets that freedom, while the right to edit executable policies stays an explicit privilege.
Technology stack
Core server
Python, Django, Django REST Framework
HTTP and process supervision
Rust, axum
Protocol gateways
Go, Rust
Frontend
TypeScript, Lit
Data and messaging
PostgreSQL
Identity protocols
OAuth2, OpenID Connect, SAML, LDAP, RADIUS
Other engagements
Recognize the pattern?
If one of these looks like your situation, the discovery call is where we find out how close.