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.
LifecycleOS models three common workforce identity events:
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.
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.
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
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 |
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.
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.
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
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.
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.
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.
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.
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
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.
LifecycleOS deliberately separates public presentation from privileged identity infrastructure.
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.
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.
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
Real Okta Management API operations execute server-side.
Sensitive credentials are never passed to React client components.
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.
Okta
OAuth 2.0
private_key_jwt
Okta Management API
Delegated Administration
Group-Based Access
Next.js 16
React
TypeScript
Tailwind CSS
Server Components
Server Actions
Vercel
GitHub
lifecycleos/
│
├── src/
│ │
│ ├── app/
│ │ ├── DemoControls.tsx
│ │ ├── actions.ts
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ │
│ └── lib/
│ ├── dashboard.ts
│ ├── lifecycle.ts
│ └── okta.ts
│
├── package.json
└── README.md
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
Contains the actual JML workflow logic.
Implements:
Create employee
Update employee profile
Assign group
Remove group
Deactivate employee
Reactivate demo employee
Reset demo environment
Converts identity state into presentation data.
Supports:
Live Okta dashboard
Public simulation dashboard
Lifecycle completion detection
Friendly lifecycle statuses
Business-access filtering
Acts as the execution boundary.
Development
→ real Okta lifecycle operations
Production
→ safe simulation operations
This prevents public users from reaching privileged identity-management functions.
Node.js
Okta Integrator Free Plan organization
Okta API Services application
Private JWK
Clone:
git clone https://github.com/haisamar/lifecycleos.git
cd lifecycleosInstall:
npm installCreate:
.env.local
Example configuration:
OKTA_ORG_URL=
OKTA_CLIENT_ID=
OKTA_PRIVATE_JWK_JSON=Do not commit this file.
Run:
npm run devOpen:
http://localhost:3000
The local environment will display:
Connected to Okta
LIVE OKTA
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.
A technical demonstration can be performed with LifecycleOS and the Okta Admin Console side-by-side.
Completed Flows: 0
Offboarded: 0
LifecycleOS creates Maya Chen.
Verify in Okta:
Maya Chen
Status: Staged
LifecycleOS:
Completed Flows: 1
LifecycleOS updates Daniel Ross.
Sales
→ Finance
and:
Account Executive
→ Financial Analyst
LifecycleOS:
Completed Flows: 2
LifecycleOS deactivates Sara Malik.
Verify in Okta:
Sara Malik
Status: Deactivated
LifecycleOS:
Completed Flows: 3
Offboarded: 1
The sandbox returns to its original state and the demonstration can be repeated.
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.
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
GitHub:
https://github.com/haisamar/lifecycleos
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.