Skip to content

Repository files navigation

LifecycleOS

Workforce identity, from first day to last.

LifecycleOS is an identity lifecycle automation project that demonstrates how Joiner, Mover, and Leaver (JML) workforce events can be translated into real identity changes in Okta.

The project includes two execution environments:

  • Live Okta mode — runs locally against a real Okta Integrator tenant and performs real identity lifecycle operations.
  • Public simulation mode — provides a fully interactive portfolio demo without exposing Okta credentials or allowing public users to modify the real tenant.

The public deployment contains no Okta credentials and performs no Okta Management API writes.


What LifecycleOS Demonstrates

LifecycleOS models three common workforce identity events:

Joiner

A new employee joins Engineering.

HR event
   ↓
Create Okta identity
   ↓
Set employee profile
   ↓
Assign Engineering
   ↓
Assign All Employees

Demo employee:

Maya Chen
Engineering
Software Engineer

The resulting Okta identity is created in the STAGED lifecycle state for the demo rather than automatically sending an activation email.


Mover

An existing employee changes departments.

Sales
Account Executive
   ↓
Role change
   ↓
Remove obsolete Sales access
   ↓
Update employee profile
   ↓
Grant Finance access

Demo employee:

Daniel Ross

Before:
Sales
Account Executive

After:
Finance
Financial Analyst

The important identity principle is that new access is not simply added on top of old access.

Obsolete access is explicitly removed.


Leaver

An employee leaves the organization.

Active workforce identity
   ↓
Deactivate Okta identity
   ↓
Remove business access groups
   ↓
Identity becomes DEPROVISIONED

Demo employee:

Sara Malik
Engineering
Software Engineer

After the Leaver workflow:

Status:
Deactivated

Business access:
Removed

Live Demo vs Public Demo

LifecycleOS intentionally separates the privileged integration from the public portfolio experience.

Environment Mode Okta Reads Okta Writes Interactive
Local development Live Okta Yes Yes Yes
Public Vercel deployment Simulation No No Yes

Local Mode

The local environment connects directly to the Okta Management API.

LifecycleOS UI
      ↓
Next.js Server Action
      ↓
Lifecycle Engine
      ↓
OAuth 2.0 Service App
      ↓
Okta Management API
      ↓
Real identity change

This mode is used for the real technical demonstration.


Public Mode

The public deployment provides the same lifecycle experience without privileged infrastructure access.

Visitor
   ↓
LifecycleOS
   ↓
Simulation action
   ↓
HttpOnly simulation state
   ↓
Dashboard state changes

No Okta API mutation occurs.

This allows recruiters and reviewers to interact with the lifecycle workflows safely.


Architecture

flowchart TB

    HR["Workforce Lifecycle Event"]

    UI["LifecycleOS<br/>Next.js UI"]

    MODE{"Execution Mode"}

    LIVE["Live Okta Mode<br/>Local Environment"]

    SIM["Portfolio Simulation<br/>Public Vercel"]

    ACTION["Server Actions"]

    ENGINE["Lifecycle Engine"]

    AUTH["OAuth 2.0 Service App<br/>private_key_jwt"]

    OKTA["Okta Management API"]

    ID["Workforce Identity"]

    GROUPS["Role-Based Groups"]

    STATE["Lifecycle State"]

    COOKIE["HttpOnly Simulation State"]

    DASH["Lifecycle Dashboard"]

    HR --> UI
    UI --> MODE

    MODE -->|"Local"| LIVE
    MODE -->|"Production"| SIM

    LIVE --> ACTION
    ACTION --> ENGINE
    ENGINE --> AUTH
    AUTH --> OKTA

    OKTA --> ID
    OKTA --> GROUPS
    OKTA --> STATE

    ID --> DASH
    GROUPS --> DASH
    STATE --> DASH

    SIM --> COOKIE
    COOKIE --> DASH
Loading

Identity Lifecycle Model

LifecycleOS separates three kinds of identity change.

JOINER
Identity does not exist
        ↓
Create identity
        ↓
Set profile
        ↓
Assign role access
MOVER
Existing identity
        ↓
Change employee attributes
        ↓
Remove obsolete access
        ↓
Assign new access
LEAVER
Existing identity
        ↓
Deactivate identity
        ↓
Remove business access

The central design principle is:

Access should follow the employee's role — and disappear when that role no longer requires it.


Okta Integration

LifecycleOS uses an Okta API Services application for server-to-server identity administration.

Authentication uses:

OAuth 2.0
Client Credentials
private_key_jwt
Asymmetric key authentication

The application requests only the management scopes required by the demo:

okta.users.manage
okta.groups.manage

The integration does not rely on a Super Administrator assignment.

Instead, delegated administrative roles are scoped to the groups required by the lifecycle automation.


Least-Privilege Administration

The service identity uses scoped administrative authority rather than unrestricted tenant administration.

Business access groups:

All Employees
Sales
Engineering
Finance

LifecycleOS also uses a separate administrative boundary:

LifecycleOS Managed

This group is not an employee business entitlement.

It exists to define which demo identities the automation is allowed to administer.

This separation became especially important during the Leaver workflow.

If an offboarded user were removed from every administrative scope the service application could manage, the automation would no longer have authority to restore that user during a sandbox reset.

LifecycleOS therefore separates:

Business access

from:

Automation management scope

This allows business access to be fully revoked while preserving the controlled administrative boundary required by the demo environment.


Real Okta Lifecycle States

LifecycleOS exposes actual Okta lifecycle behavior rather than replacing it with generic application statuses.

Examples include:

STAGED

Used by the Joiner demo when Maya is created without automatically activating the account.

PROVISIONED

Used for identities awaiting completion of the activation lifecycle.

DEPROVISIONED

Used after the Leaver workflow deactivates an identity.

The UI translates these into recruiter-friendly labels such as:

Awaiting Activation
Pending User Action
Deactivated

while retaining the underlying Okta state internally.


Direct Identity Lookup

One implementation detail exposed an important identity-management edge case.

Okta user-list queries may not behave the same way for deprovisioned identities as direct identity retrieval.

After Sara was deactivated, LifecycleOS therefore changed from broad user enumeration to direct identity lookup.

Conceptually:

Before

List users
   ↓
Search returned results

became:

After

Retrieve exact identity by login
   ↓
Read lifecycle state directly

This allows the dashboard to correctly recognize:

DEPROVISIONED

and report:

Completed Flows: 3
Offboarded: 1

Demo Reset

LifecycleOS includes a sandbox-only reset mechanism so the JML demonstration can be repeated.

The reset restores:

Maya Chen
→ removed

Daniel Ross
→ Sales
→ Account Executive

Sara Malik
→ reactivated
→ Engineering
→ Software Engineer

The complete demo cycle is therefore repeatable:

Reset
  ↓
Completed Flows: 0

Joiner
  ↓
Completed Flows: 1

Mover
  ↓
Completed Flows: 2

Leaver
  ↓
Completed Flows: 3
Offboarded: 1

Reset
  ↓
Completed Flows: 0

The reset functionality exists strictly for the controlled demonstration environment.


Security Boundaries

LifecycleOS deliberately separates public presentation from privileged identity infrastructure.

No public mutation endpoints

Temporary development API routes were removed before deployment.

The application does not publicly expose routes such as:

/api/lifecycle/joiner
/api/lifecycle/mover
/api/lifecycle/leaver

Lifecycle actions are performed through server-side application logic.


No Okta credentials in the public deployment

The public Vercel simulation does not store:

Okta organization URL
Okta service application client ID
Okta private JWK

The real Okta credentials exist only in the controlled local development environment.


Private key authentication

The live integration uses an asymmetric private JWK rather than a client secret.

The private key:

is not committed to Git
is not included in the repository
is not exposed to browser JavaScript
is not stored in the public Vercel project

Server-side identity operations

Real Okta Management API operations execute server-side.

Sensitive credentials are never passed to React client components.


Public simulation isolation

The public portfolio demo stores only simulation progress.

Example:

J = Joiner completed
M = Mover completed
L = Leaver completed

This state does not correspond to privileged Okta credentials or API authorization.


Technology

Identity

Okta
OAuth 2.0
private_key_jwt
Okta Management API
Delegated Administration
Group-Based Access

Application

Next.js 16
React
TypeScript
Tailwind CSS
Server Components
Server Actions

Deployment

Vercel
GitHub

Repository Structure

lifecycleos/
│
├── src/
│   │
│   ├── app/
│   │   ├── DemoControls.tsx
│   │   ├── actions.ts
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   └── page.tsx
│   │
│   └── lib/
│       ├── dashboard.ts
│       ├── lifecycle.ts
│       └── okta.ts
│
├── package.json
└── README.md

Core Components

okta.ts

Responsible for the machine-to-machine Okta authentication layer.

Implements:

private JWK loading
private_key_jwt assertion creation
OAuth access-token request
authenticated Okta API requests

lifecycle.ts

Contains the actual JML workflow logic.

Implements:

Create employee
Update employee profile
Assign group
Remove group
Deactivate employee
Reactivate demo employee
Reset demo environment

dashboard.ts

Converts identity state into presentation data.

Supports:

Live Okta dashboard
Public simulation dashboard
Lifecycle completion detection
Friendly lifecycle statuses
Business-access filtering

actions.ts

Acts as the execution boundary.

Development
→ real Okta lifecycle operations

Production
→ safe simulation operations

This prevents public users from reaching privileged identity-management functions.


Local Development

Requirements

Node.js
Okta Integrator Free Plan organization
Okta API Services application
Private JWK

Clone:

git clone https://github.com/haisamar/lifecycleos.git
cd lifecycleos

Install:

npm install

Create:

.env.local

Example configuration:

OKTA_ORG_URL=
OKTA_CLIENT_ID=
OKTA_PRIVATE_JWK_JSON=

Do not commit this file.

Run:

npm run dev

Open:

http://localhost:3000

The local environment will display:

Connected to Okta
LIVE OKTA

Public Portfolio

The production deployment automatically enters:

SIMULATION

rather than live Okta mode.

Visitors can interact with all three lifecycle scenarios without receiving Okta administrative privileges.

The UI clearly identifies the environment as:

Okta Workflow Simulation

and:

Portfolio simulation — no changes are made to the connected Okta tenant.

Demo Walkthrough

A technical demonstration can be performed with LifecycleOS and the Okta Admin Console side-by-side.

1. Reset

Completed Flows: 0
Offboarded: 0

2. Run Joiner

LifecycleOS creates Maya Chen.

Verify in Okta:

Maya Chen
Status: Staged

LifecycleOS:

Completed Flows: 1

3. Run Mover

LifecycleOS updates Daniel Ross.

Sales
→ Finance

and:

Account Executive
→ Financial Analyst

LifecycleOS:

Completed Flows: 2

4. Run Leaver

LifecycleOS deactivates Sara Malik.

Verify in Okta:

Sara Malik
Status: Deactivated

LifecycleOS:

Completed Flows: 3
Offboarded: 1

5. Reset

The sandbox returns to its original state and the demonstration can be repeated.


Why This Project Exists

Identity lifecycle automation is not only about creating accounts.

The harder problem is keeping identity and access aligned with changes in the workforce.

A system needs to answer:

Who should have access?

What access should they have?

What access should they no longer have?

What happens when their role changes?

What happens when they leave?

LifecycleOS demonstrates those questions through a small but complete workforce identity lifecycle.


Key Identity Concepts Demonstrated

Joiner / Mover / Leaver automation
Identity lifecycle states
Role-based group assignment
Access reconciliation
Least privilege
Delegated administration
Machine-to-machine authentication
OAuth 2.0
private_key_jwt
Deprovisioning
Administrative scope separation
Public / privileged environment separation

Repository

GitHub:

https://github.com/haisamar/lifecycleos


Disclaimer

LifecycleOS is an identity engineering portfolio project and controlled demonstration environment.

The reset workflows and demo identities are designed for a sandbox Okta tenant and should not be applied indiscriminately to production workforce identities.

About

Okta-powered Joiner, Mover, and Leaver identity lifecycle automation with least-privilege delegated administration and a safe public simulation.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages