Developer Handover Pack
Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.
Developer Handover Pack
Password Reset & Access Requests
[YourCompany.com] · IT Department · Prepared by FullSpec · [Today's Date]
This document gives the FullSpec build team every specification needed to construct, wire, and test the three-agent Password Reset and Access Request automation. It covers the current-state process with bottlenecks identified, full agent specifications including triggers, tooling, IO contracts, and implementation constraints, the end-to-end data flow traced field by field, and the recommended build stack with estimated hours. The process owner's role is to confirm API access and service account details before build starts; everything else is handled by FullSpec.
01Process snapshot
02Agent specifications
Receives inbound requests from either the Slack slash command (/it-request) or the web intake form, classifies the request as a password reset or a new access request, extracts the relevant structured details (requester identity, system name, urgency), and creates a populated Jira ticket. Eliminates all manual reading, copying, and triage so that no human intervention is required at the top of the funnel. Complexity: Moderate.
// Input
slack_payload: {
user_id: string, // Slack user ID of requester
user_name: string, // Display name
command: '/it-request',
text: string, // Raw request text from slash command
response_url: string, // Ephemeral reply endpoint
trigger_id: string // Used to open modal if needed
}
// OR form_submission: {
requester_email: string,
request_type: 'password_reset' | 'new_access',
system_name: string,
urgency: 'normal' | 'urgent',
additional_notes: string
}
// Output
jira_ticket: {
ticket_id: string, // e.g. 'IT-4821'
summary: string, // Auto-generated from classification
request_type: 'password_reset' | 'new_access',
requester_slack_id: string,
requester_email: string,
system_name: string,
status: 'Open',
created_at: ISO8601,
source_channel: 'slack_command' | 'web_form'
}- Slack app must be installed at the workspace level with the slash command /it-request registered. The OAuth scopes required are commands, chat:write, users:read, and users:read.email. Confirm with the process owner before build.
- Jira integration requires a service account with project-level Create Issue and Edit Issue permissions on the IT helpdesk project. Use API token authentication (not OAuth) for server-to-server calls.
- Classification logic must handle ambiguous text. If the request cannot be classified with confidence, default to request_type: 'new_access' and flag the ticket with a 'REVIEW_NEEDED' label rather than dropping or misrouting it.
- Web form fallback must be built alongside the Slack command. Teams that do not use Slack daily need this path. The form should post to the same webhook endpoint as the Slack trigger to avoid duplicating downstream logic.
- Dedupe check: if a Jira ticket already exists for the same requester_email with status 'Open' and the same system_name, link to the existing ticket rather than creating a duplicate. Surface a Slack message to the requester confirming their existing ticket ID.
- Confirm the Jira project key and board ID with the process owner during discovery before wiring the ticket creation call.
Handles two parallel verification paths based on the ticket's request_type. For password resets, it triggers an Okta identity verification challenge to the requester's registered MFA device or secondary email without any IT involvement. For new access requests, it sends the requester's direct manager a structured Slack message containing the ticket summary and one-click Approve or Deny buttons. Monitors for responses, sends a single automated reminder after 2 hours of no response, and escalates to the IT escalation queue after 24 hours. Records the outcome on the Jira ticket before handing off. Complexity: Complex.
// Input
jira_ticket: {
ticket_id: string,
request_type: 'password_reset' | 'new_access',
requester_email: string,
requester_slack_id: string,
system_name: string
}
// On password_reset branch:
okta_authn_response: {
status: 'SUCCESS' | 'MFA_CHALLENGE' | 'LOCKED_OUT',
session_token: string | null,
factor_type: 'email' | 'sms' | 'totp'
}
// On new_access branch:
azure_ad_manager: {
manager_email: string,
manager_slack_id: string, // Looked up via Slack users.lookupByEmail
manager_display_name: string
}
slack_approval_response: {
action_id: 'approve' | 'deny',
responder_slack_id: string,
responded_at: ISO8601,
ticket_id: string
}
// Output
verification_result: {
ticket_id: string,
outcome: 'verified' | 'approved' | 'denied' | 'failed' | 'timeout',
method: 'okta_mfa' | 'manager_slack_approval',
decided_by: string, // email of approver or 'okta_system'
decided_at: ISO8601
}- Okta service account must have the SUPER_ADMIN or APP_ADMIN role scoped to the relevant application. Confirm the minimum required scope with the Okta admin before build. The /api/v1/authn endpoint is used to initiate the identity challenge; do not use the /api/v1/sessions endpoint for this flow.
- Manager resolution uses the Azure AD Graph API (GET /v1.0/users/{requester_email}/manager). Requires the application registration to hold the User.Read.All delegated permission. If the manager field is null or the manager is not a Slack user, route the ticket immediately to the IT escalation queue rather than waiting for a timeout.
- Slack interactive message buttons must use Block Kit with action_id values 'it_approve' and 'it_deny'. The Slack app's Request URL for interactive components must point to the automation platform's webhook endpoint. Confirm this URL is reachable from Slack's servers (public HTTPS, valid TLS).
- Reminder timing: send one Slack reminder to the manager after 2 hours of no response. Do not send more than one reminder. After 24 hours with no response, update the Jira ticket status to 'Escalated' and post to the IT escalation channel with the ticket ID.
- Denial and failure handling: if the manager clicks Deny, or if the Okta MFA challenge returns a LOCKED_OUT or failed status, set verification_result.outcome to 'denied' or 'failed', update the Jira ticket with the reason, and route to the IT escalation Slack channel. Do not proceed to provisioning.
- The Okta MFA challenge link sent to the requester must expire after 15 minutes. If expired, the agent must generate a new challenge link and notify the requester via Slack before retrying.
Executes the approved access change across Okta and Google Workspace, notifies the requester with a formatted Slack message, and closes the Jira ticket with a complete audit log entry. This agent only runs when verification_result.outcome is 'verified' or 'approved'. If the outcome is anything else, this agent does not execute and the escalation path handles the ticket. Complexity: Moderate.
// Input
verification_result: {
ticket_id: string,
outcome: 'verified' | 'approved',
method: 'okta_mfa' | 'manager_slack_approval',
decided_by: string,
decided_at: ISO8601
}
jira_ticket: {
request_type: 'password_reset' | 'new_access',
requester_email: string,
requester_slack_id: string,
system_name: string,
ticket_id: string
}
// On password_reset branch:
okta_reset_response: {
reset_password_url: string, // Temporary link sent to requester
expires_at: ISO8601
}
// On new_access branch:
okta_role_response: {
role_id: string,
assigned_at: ISO8601
}
google_workspace_response: {
group_email: string, // Group the user was added to
membership_status: 'ACTIVE'
}
// Output
audit_record: {
ticket_id: string,
action_taken: string, // Human-readable summary
okta_change: string, // Role or reset reference
google_workspace_change: string | null,
approved_by: string, // decided_by from verification_result
approval_method: string,
executed_at: ISO8601,
jira_status: 'Done',
slack_confirmation_sent: boolean
}- Okta provisioning calls require a service account with the USER_ADMIN role at minimum. The resetPassword lifecycle endpoint returns a temporary password reset URL that must be included in the Slack confirmation to the requester, not stored in the audit log.
- Google Workspace Admin SDK requires a service account with domain-wide delegation enabled and the scope https://www.googleapis.com/auth/admin.directory.group.member for group membership changes. The group_email value to use for each system_name must be maintained in a lookup table in the automation platform's credential store.
- Jira ticket close must use the correct transition ID for the 'Done' status in the configured workflow. Fetch available transitions via GET /rest/api/3/issue/{ticket_id}/transitions before wiring the close call; do not hardcode the transition ID as it varies by project.
- Slack confirmation message must use a Block Kit template that includes: the action taken, the system name, the approval method, and any next steps (e.g. 'Set your new password using the link below. It expires in 60 minutes.'). Use a consistent message template across all runs.
- If the Okta provisioning call fails (non-2xx response), do not close the Jira ticket. Instead, transition it to 'Failed', post an alert to the IT escalation Slack channel with the error detail, and stop. Do not retry more than once automatically.
- Audit note written to Jira must record: action taken, system name, approval method, approved_by email, executed_at timestamp, and the Okta or Google Workspace reference ID. This is the compliance-facing record and must be complete on every run.
03End-to-end data flow
// ============================================================
// TRIGGER: Staff member submits Slack slash command or web form
// ============================================================
INPUT {
source: 'slack_command' | 'web_form'
user_id: string // Slack user ID
user_name: string
requester_email: string // Resolved via Slack users.info if source=slack_command
text: string // Raw request text
trigger_id: string // Slack modal opener (if needed)
}
// ============================================================
// AGENT 1: Request Intake Agent
// ============================================================
// Classification step
classify(text) -> request_type: 'password_reset' | 'new_access'
classify(text) -> system_name: string
classify(text) -> urgency: 'normal' | 'urgent'
// Dedupe check
GET /rest/api/3/issue/search?jql=project=IT AND status=Open
AND reporter.email={requester_email} AND summary~{system_name}
-> existing_ticket_id: string | null
IF existing_ticket_id != null -> notify requester, STOP
// Jira ticket creation
POST /rest/api/3/issue
BODY {
fields.project.key: 'IT'
fields.summary: '[{request_type}] {system_name} - {user_name}'
fields.issuetype.name: 'IT Request'
fields.description: {text}
fields.customfield_requester_email: {requester_email}
fields.customfield_requester_slack_id: {user_id}
fields.customfield_request_type: {request_type}
fields.customfield_system_name: {system_name}
fields.customfield_source_channel: {source}
}
-> ticket_id: string // e.g. 'IT-4821'
-> jira_ticket_url: string
// HANDOFF 1->2: ticket_id, request_type, requester_email,
// requester_slack_id, system_name
// ============================================================
// AGENT 2: Verification and Approval Agent
// ============================================================
IF request_type == 'password_reset' {
// Okta MFA challenge
POST /api/v1/authn
BODY { username: {requester_email}, password: null }
-> stateToken: string
POST /api/v1/authn/factors/{factorId}/verify
BODY { stateToken: {stateToken} }
-> status: 'SUCCESS' | 'MFA_CHALLENGE' | 'LOCKED_OUT'
-> sessionToken: string | null
// Challenge link expires: 15 minutes
}
IF request_type == 'new_access' {
// Resolve manager from Azure AD
GET /v1.0/users/{requester_email}/manager
-> manager_email: string
-> manager_display_name: string
// Resolve manager Slack ID
GET /api/v1/users.lookupByEmail?email={manager_email}
-> manager_slack_id: string
// Send approval message
POST /api/v1/chat.postMessage
BODY {
channel: {manager_slack_id}
blocks: [Block Kit approval card with ticket_id, requester, system_name]
actions: [{ action_id: 'it_approve' }, { action_id: 'it_deny' }]
}
// Wait for interactive callback (2hr reminder, 24hr escalation)
<- slack_callback: { action_id, responder_slack_id, responded_at }
}
// Outcome written back to Jira
POST /rest/api/3/issue/{ticket_id}/comment
BODY { body: 'Verification outcome: {outcome} via {method} at {decided_at}' }
IF outcome IN ['denied','failed','timeout'] {
// Transition ticket to 'Escalated', alert IT escalation channel
POST /api/v1/chat.postMessage -> channel: '#it-escalations'
STOP
}
// HANDOFF 2->3: ticket_id, request_type, requester_email,
// requester_slack_id, system_name, outcome,
// method, decided_by, decided_at
// ============================================================
// AGENT 3: Provisioning and Audit Agent
// ============================================================
IF request_type == 'password_reset' {
POST /api/v1/users/{okta_user_id}/lifecycle/resetPassword?sendEmail=false
-> reset_password_url: string
-> expires_at: ISO8601
}
IF request_type == 'new_access' {
// Okta role assignment
POST /api/v1/users/{okta_user_id}/roles
BODY { type: {mapped_role_for_system_name} }
-> role_id: string
-> assigned_at: ISO8601
// Google Workspace group membership
POST /admin/directory/v1/groups/{group_email}/members
BODY { email: {requester_email}, role: 'MEMBER' }
-> membership_status: 'ACTIVE'
}
// Slack confirmation to requester
POST /api/v1/chat.postMessage
BODY {
channel: {requester_slack_id}
blocks: [Block Kit confirmation card with action_taken,
system_name, reset_password_url (if reset), next_steps]
}
-> slack_confirmation_sent: true
// Jira audit note + close
POST /rest/api/3/issue/{ticket_id}/comment
BODY { body: audit_note_string } // action, system, approved_by, okta_ref, gws_ref, executed_at
POST /rest/api/3/issue/{ticket_id}/transitions
BODY { transition: { id: {done_transition_id} } }
-> jira_status: 'Done'
// ============================================================
// FINAL OUTPUT: audit_record persisted in Jira; requester unblocked
// ============================================================04Recommended build stack
More documents for this process
Every document generated for Password Reset & Access Requests.