Example: Provisioning Workflow with Role & Entitlement Lifecycle¶
A comprehensive workflow that invites a user to join a research program, collects required compliance documents, routes them through approval, and automatically provisions role-based access across multiple systems — with document-driven expiry that revokes access when certifications lapse.
Use Case¶
A compliance officer needs to onboard a researcher into the Genome Access Program. The researcher must:
- Accept an invitation to participate
- Submit a signed data use agreement (DUA) valid for one year
- Submit a current human subjects training certificate valid for two years
- Receive approval from a designated reviewer on both documents
Upon approval, the researcher is automatically granted the Genome Access Participant role, which provisions:
- Membership in the
genome-accessAuthifi group (grants SSO access to the genomics portal) - An Active Directory account in the
RESEARCH\GenomeUsersOU (grants access to the secure file share)
When either document expires, the role is automatically revoked and both entitlements are deprovisioned.
Prerequisites¶
- Authifi connector configured with valid client credentials and the target tenant
- Test Active Directory connector configured (or a real AD connector in production)
- The
genome-accessgroup exists in Authifi - Role Definition "Genome Access Participant" created with two entitlements:
- Authifi group membership (
addToGroup/removeFromGroup/checkGroupMembership) - AD account (
createAccount/disableAccount/checkAccountExists)
Creating Entitlement Definitions¶
Entitlements are first-class, shared objects that can be linked to multiple roles. Create them via the Entitlements page (/entitlements) before building the role.
Entitlement 1: Authifi Group
- Click New Entitlement
- Fill in:
| Field | Value |
|---|---|
| Name | Genomics Portal Access |
| Connector | authifi |
| Provision Config | { "command": "addToGroup", "groupId": "<genome-access-group-id>", "role": "member", "createIfMissing": true } |
| Deprovision Config | { "command": "removeFromGroup", "groupId": "<genome-access-group-id>" } |
| Reconciliation Config | { "command": "checkGroupMembership", "groupId": "<genome-access-group-id>" } |
Entitlement 2: AD Account
- Click New Entitlement
- Fill in:
| Field | Value |
|---|---|
| Name | Research File Share Access |
| Connector | test-activedirectory |
| Provision Config | { "command": "createAccount", "ou": "RESEARCH\\GenomeUsers", "groupName": "GenomeAccess" } |
| Deprovision Config | { "command": "removeFromGroup", "groupName": "GenomeAccess" } |
| Reconciliation Config | { "command": "checkGroupMembership", "groupName": "GenomeAccess" } |
Creating the Role Definition¶
After creating the entitlement definitions, create the role and link them:
- Navigate to Role Definitions (
/roles) and click New Role - Fill in:
- Name:
Genome Access Participant - Description:
Grants access to the genomics portal and secure file share - Expires After (days): leave blank (expiry is driven by document lifecycle, not a fixed TTL)
- Save, then open the role detail page
- Click Link Entitlement and search for each entitlement created above:
- Link
Genomics Portal Access - Link
Research File Share Access
Note the role definition ID after saving — you'll reference it in the role_grant step.
Workflow Settings¶
| Field | Value |
|---|---|
| Name | Genome Access Provisioning |
| Category | user |
| Subject Variable | user (auto-created) |
| Error Strategy | stop |
| Trigger | manual |
Context Variables¶
| Name | Type | Required | Description |
|---|---|---|---|
user |
User | yes | The researcher being onboarded (auto-created, workflow subject) |
reviewer |
User | yes | The compliance reviewer who approves the documents |
Workflow Steps¶
| # | Step Name | Type | Purpose |
|---|---|---|---|
| 1 | Start | start |
Entry point |
| 2 | Send Program Invitation | notification |
Invites the researcher; pauses until accepted |
| 3 | Check Invitation | condition |
Branches on acceptance |
| 4 | Request Data Use Agreement | document_submission |
Collects the signed DUA (expires in 365 days) |
| 5 | Request Training Certificate | document_submission |
Collects the human subjects certificate (expires in 730 days) |
| 6 | Grant Genome Access Role | role_grant |
Provisions all entitlements via connectors |
| 7 | Send Access Granted Email | notification |
Confirms provisioning to the researcher |
| 8 | Send DUA Rejected Email | notification |
Notifies researcher of DUA rejection |
| 9 | Send Training Rejected Email | notification |
Notifies researcher of training rejection |
| 10 | Send Declined Email | notification |
Notifies researcher if they declined the invitation |
| 11 | End | end |
Exit point |
Flow Diagram¶
Start
│
▼
Send Program Invitation (notification, requiresAcceptance)
│
▼
Check Invitation (condition: acceptance_status == "accepted")
│
├── true ──► Request Data Use Agreement (document_submission, expiresAfterDays: 365)
│ │
│ ├── success ──► Request Training Certificate (document_submission, expiresAfterDays: 730)
│ │ │
│ │ ├── success ──► Grant Genome Access Role (role_grant)
│ │ │ │
│ │ │ └──► Send Access Granted Email ──► End
│ │ │
│ │ └── error ──► Send Training Rejected Email ──► End
│ │
│ └── error ──► Send DUA Rejected Email ──► End
│
└── false ──► Send Declined Email ──► End
Step-by-Step Configuration¶
Step 2: Send Program Invitation¶
| Config Field | Value |
|---|---|
| Type | notification |
| Recipient Type | Internal User |
| Recipient User | {{user.id}} |
| Subject Override | Invitation to the Genome Access Program |
| Custom Body | You have been invited to join the Genome Access Program. Participation requires submission and approval of a Data Use Agreement and a current Human Subjects Training Certificate. Click the link below to accept this invitation and begin the enrollment process. |
| Require User Acceptance | Checked (true) |
| Acceptance Expiry (hours) | 168 (7 days) |
The workflow pauses at waiting_acceptance. The researcher receives an email with an accept/reject link. If they don't respond within 7 days, the acceptance expires and the condition evaluates to the false branch.
Step 3: Check Invitation¶
| Config Field | Value |
|---|---|
| Type | condition |
| Expression | acceptance_status == "accepted" |
| True → Go To | Request Data Use Agreement |
| False → Go To | Send Declined Email |
Step 4: Request Data Use Agreement¶
| Config Field | Value |
|---|---|
| Type | document_submission |
| Document Label | Signed Data Use Agreement |
| Instructions | Download the Data Use Agreement template, read it carefully, sign it, and upload the signed copy as a PDF. This agreement is valid for one year from the date of approval. |
| Template ID | (select your DUA template from the dropdown, if uploaded) |
| Submitter Email | {{user.email}} |
| Submitter User ID | {{user.id}} |
| Allowed MIME Types | application/pdf |
| Max File Size | 10485760 (10 MB) |
| Approvers | {{reviewer.id}} |
| Notify Submitter | Checked |
| Notify Approvers | Checked |
| Expires After (days) | 365 |
| Success → Go To | Request Training Certificate |
| Error → Go To | Send DUA Rejected Email |
The expiresAfterDays: 365 setting automatically stamps each uploaded document with an expires_at date one year from upload. The hourly document-expiry-check job monitors this expiry and triggers revocation of any linked role assignments when the document lapses.
Step 5: Request Training Certificate¶
| Config Field | Value |
|---|---|
| Type | document_submission |
| Document Label | Human Subjects Training Certificate |
| Instructions | Complete the required human subjects protection training and upload your certificate of completion. Certificates are valid for two years. |
| Template URL | https://training.example.com/human-subjects |
| Submitter Email | {{user.email}} |
| Submitter User ID | {{user.id}} |
| Allowed MIME Types | application/pdf, image/* |
| Max File Size | 5242880 (5 MB) |
| Approvers | {{reviewer.id}} |
| Notify Submitter | Checked |
| Notify Approvers | Checked |
| Expires After (days) | 730 |
| Success → Go To | Grant Genome Access Role |
| Error → Go To | Send Training Rejected Email |
Step 6: Grant Genome Access Role¶
| Config Field | Value |
|---|---|
| Type | role_grant |
| Role Definition ID | (UUID of "Genome Access Participant" — paste or use variable) |
| User ID | {{user.id}} |
| Fail on Partial | Unchecked (false) |
| Next Step | Send Access Granted Email |
This step calls RoleService.grantRole(), which:
- Creates a
role_assignmentrecord linked to this workflow run - For each entitlement definition on the role:
- Creates an
entitlement_instancewith statuspending - Executes the connector command from
provision_config - Updates the instance to
provisioned(orfailed) - Sets the assignment status to
active(orpartially_provisionedif any entitlement failed)
The step produces output variables (roleAssignmentId, roleProvisioned, provisionedCount, failedCount) that can be referenced by subsequent steps.
With failOnPartial unchecked, the workflow continues even if one entitlement fails to provision. The failed entitlement can be reprovisioned later from the Role Assignments page.
Step 7: Send Access Granted Email¶
| Config Field | Value |
|---|---|
| Type | notification |
| Recipient Type | Internal User |
| Recipient User | {{user.id}} |
| Subject Override | Genome Access Program — Access Granted |
| Custom Body | Your documents have been approved and your access has been provisioned. You now have access to the Genomics Portal and the Research File Share. Your Data Use Agreement expires in 1 year and your Training Certificate expires in 2 years — you will need to renew them before expiry to maintain access. |
| Require User Acceptance | Unchecked (false) |
Step 8: Send DUA Rejected Email¶
| Config Field | Value |
|---|---|
| Type | notification |
| Recipient Type | Internal User |
| Recipient User | {{user.id}} |
| Subject Override | Data Use Agreement not approved |
| Custom Body | Your submitted Data Use Agreement for the Genome Access Program was not approved. Please review the reviewer's feedback, make corrections, and contact the compliance office for next steps. |
| Require User Acceptance | Unchecked (false) |
Step 9: Send Training Rejected Email¶
| Config Field | Value |
|---|---|
| Type | notification |
| Recipient Type | Internal User |
| Recipient User | {{user.id}} |
| Subject Override | Training certificate not approved |
| Custom Body | Your Human Subjects Training Certificate was not approved. Please verify that you completed the correct training course and that the certificate is current. Contact the compliance office if you need assistance. |
| Require User Acceptance | Unchecked (false) |
Step 10: Send Declined Email¶
| Config Field | Value |
|---|---|
| Type | notification |
| Recipient Type | Internal User |
| Recipient User | {{user.id}} |
| Subject Override | Genome Access Program invitation declined |
| Custom Body | We received your response declining the invitation to the Genome Access Program. If this was a mistake or you change your mind, please contact the compliance office to receive a new invitation. |
| Require User Acceptance | Unchecked (false) |
Wiring the Graph¶
Connect the steps in the graph editor:
- Start → Send Program Invitation
- Send Program Invitation → Check Invitation
- Check Invitation → true → Request Data Use Agreement
- Check Invitation → false → Send Declined Email
- Request Data Use Agreement → success → Request Training Certificate
- Request Data Use Agreement → error → Send DUA Rejected Email
- Request Training Certificate → success → Grant Genome Access Role
- Request Training Certificate → error → Send Training Rejected Email
- Grant Genome Access Role → Send Access Granted Email
- Send Access Granted Email → End
- Send DUA Rejected Email → End
- Send Training Rejected Email → End
- Send Declined Email → End
Starting a Run¶
Start the workflow manually from the workflow detail page or via API:
POST /api/workflows/:id/start
{
"variables": {
"user": "uuid-of-researcher",
"reviewer": "uuid-of-compliance-reviewer"
}
}
For user-type variables, supply the user's UUID; the engine resolves it to a full user object (with id, email, displayName, etc.) before execution begins.
If the researcher doesn't have an account yet, pre-provision one:
POST /api/users
{ "email": "researcher@university.edu", "displayName": "Dr. Jane Smith" }
# → { "id": "newly-created-uuid", ... }
Runtime Walkthrough¶
Happy Path¶
-
Invitation sent — The engine sends an email to
researcher@university.eduwith an accept/reject link. The run pauses atwaiting_acceptance. -
Researcher accepts — Dr. Smith clicks the link and accepts. The engine resumes and evaluates the condition →
true. -
DUA requested — The engine creates a task in Dr. Smith's inbox asking her to download the DUA template, sign it, and upload it. The run pauses at
waiting_submission. -
DUA uploaded — Dr. Smith uploads the signed PDF. The document is stored with
expires_atset to 365 days from now andsubject_user_idset to her user ID. The run transitions towaiting_approvaland the reviewer is notified. -
DUA approved — The reviewer downloads the DUA, verifies the signature, and clicks Approve. The engine resumes and moves to the next document.
-
Training certificate requested — Another task appears in Dr. Smith's inbox. She completes the training at the linked URL, downloads her certificate, and uploads it. This document gets
expires_atset to 730 days. -
Training approved — The reviewer approves the certificate.
-
Role granted — The
role_grantstep executes: - Creates a
role_assignmentrecord for "Genome Access Participant" linked to this run - Calls the Authifi connector's
addToGroup→ Dr. Smith is added togenome-accessgroup - Calls the AD connector's
createAccount→ an AD account is created in theGenomeUsersOU - Both
entitlement_instancerecords are markedprovisioned -
The assignment status is set to
active -
Confirmation sent — Dr. Smith receives an email confirming her access. The run completes.
Rejection Paths¶
- If Dr. Smith declines the invitation, she receives a "declined" email and the workflow ends without any document collection or provisioning.
- If the DUA is rejected, she receives a rejection email. The workflow ends — the training certificate is never requested and no access is provisioned.
- If the training certificate is rejected, she receives a rejection email. Even though the DUA was approved, no role is granted because the workflow requires both documents.
Automatic Lifecycle Management¶
After the workflow completes and access is provisioned, three automated systems monitor the ongoing lifecycle:
Document Expiry¶
The document-expiry-check scheduled job runs hourly. When Dr. Smith's DUA expires (1 year after upload):
- The job detects
expires_at < now()for the approved DUA - The document status is updated to
expired - The job finds the role assignment linked to the same workflow run via
granted_by_run_id RoleService.revokeRole()is called, which:- Calls Authifi
removeFromGroup→ Dr. Smith is removed fromgenome-access - Calls AD
removeFromGroup→ her AD group membership is removed - The role assignment status is set to
revoked
The same would happen if the training certificate expires first (at the 2-year mark). Either document expiring triggers full revocation because the role is linked to the workflow run that collected both documents.
Entitlement Reconciliation¶
The entitlement-reconciliation job runs daily at 02:00 UTC. For each active entitlement instance with a reconciliation_config:
- Calls Authifi
checkGroupMembership→ verifies Dr. Smith is still ingenome-access - Calls AD
checkGroupMembership→ verifies her AD group membership
If an entitlement is found to be missing (e.g., an Authifi admin manually removed her from the group):
- The entitlement instance is marked
orphaned - An administrator can view orphaned entitlements on the Role Assignments page and choose to reprovision (re-add to group) or revoke (remove the entire role)
Webhook Events¶
If the Authifi system supports outbound webhooks, it can notify Floh directly when group membership changes:
POST /api/entitlements/webhook/authifi-connector-id
{
"action": "removed",
"resourceId": "genome-access-group-membership-id"
}
The system correlates the resourceId with the external_id stored on the entitlement instance and marks it as orphaned immediately, without waiting for the next reconciliation cycle.
Renewal¶
When a document is approaching expiry, administrators can see it in the Documents page (/documents) with an amber "expiring soon" badge. To renew access:
- Start a new run of the same workflow (or a dedicated renewal workflow) for the same user
- The researcher submits a new, current document
- Upon approval, a new
role_grantstep provisions fresh entitlements (or the existing assignment is still active if the old document hasn't expired yet)
The expired document from the previous run does not affect the new assignment — each workflow run creates its own independent role assignment.
Monitoring Access¶
Documents Page¶
Navigate to Documents (/documents) to see all documents across users:
- Filter by Expiring Soon to see documents expiring within 30 days
- Filter by User to see all documents for a specific researcher
- Each document shows its linked role assignments and their status
Role Assignments Page¶
Navigate to Role Assignments (/role-assignments) to see all active, expired, and revoked assignments:
- Filter by Status to find
active,partially_provisioned, orrevokedassignments - Click an assignment to see individual entitlement instance statuses and reconciliation history
- Use Revoke to manually remove access, or Reprovision to fix failed/orphaned entitlements