Integration Guide¶
API Overview¶
All API endpoints are available at /api/. Authentication endpoints are at /api/auth.
Authentication is via IDP-issued access tokens. The Floh web UI uses httpOnly session cookies (BFF pattern). External API clients use Authorization: Bearer <token> with a valid IDP access token. See External API Access for details.
Interactive API Documentation¶
The server provides auto-generated OpenAPI 3.0 documentation via Swagger UI:
| Resource | URL |
|---|---|
| Swagger UI (interactive explorer) | https://<host>:3000/api/docs |
| OpenAPI JSON spec (machine-readable) | https://<host>:3000/api/docs/json |
For local development this is https://localhost:3000/api/docs. The Swagger UI lets you browse all endpoints grouped by tag, inspect request/response schemas, and try out API calls directly. The JSON spec can be imported into tools like Postman, Insomnia, or used with OpenAPI code generators.
Endpoints¶
Auth (at /api/auth, not versioned)¶
GET /api/auth/config— check if OIDC is enabledGET /api/auth/login— redirect to OIDC loginGET /api/auth/callback— OIDC callback (handles code exchange)GET /api/auth/me— current user infoPOST /api/auth/logout— logout
Workflows¶
GET /api/workflows— list definitions (paginated)POST /api/workflows— create definitionGET /api/workflows/:id— get definitionPUT /api/workflows/:id— update definition (draft only)POST /api/workflows/:id/publish— publish (draft → active)POST /api/workflows/:id/start— start runDELETE /api/workflows/:id— delete definition
Runs¶
GET /api/runs— list runs (paginated, filterable by status, definitionId)GET /api/runs/:id— get runPUT /api/runs/:id— edit run variables (pending/running only)POST /api/runs/:id/cancel— cancel run
Tasks & Approvals¶
GET /api/tasks— list assigned tasksPOST /api/tasks/:id/complete— complete taskGET /api/approvals— list pending approvalsPOST /api/approvals/:id/decide— approve/reject
Other¶
GET /api/users,PATCH /api/users/:id/rolesGET /api/connectors,POST /api/connectors,POST /api/connectors/:id/testGET /api/schedules,POST /api/schedules,PATCH /api/schedules/:idGET /api/audit-logs— with filtersGET /api/reports/*— workflow-stats, sla-compliance, approver-performanceGET /api/health— health check
Roles, Permissions & OIDC Group Mapping¶
Roles¶
Floh has four built-in roles. Each role grants a fixed set of permissions.
| Role | Description |
|---|---|
admin |
Full system access (all permissions) |
approver |
Reviews and decides on approval steps |
resource_manager |
Creates and manages workflow definitions, schedules, and reports |
requestor |
Initiates workflows and completes assigned tasks |
Permissions by Role¶
| Permission | admin | approver | resource_manager | requestor |
|---|---|---|---|---|
workflow:create |
x | x | ||
workflow:read |
x | x | x | x |
workflow:update |
x | x | ||
workflow:delete |
x | |||
workflow:publish |
x | x | ||
workflow:start |
x | x | x | |
workflow:move |
x | |||
run:read |
x | x | x | x |
run:cancel |
x | |||
run:update |
x | |||
task:read |
x | x | x | x |
task:complete |
x | x | x | |
approval:read |
x | x | ||
approval:decide |
x | x | ||
project:create |
x | |||
project:read |
x | x | x | x |
project:update |
x | |||
project:delete |
x | |||
workflow_set:manage |
x | |||
user:read |
x | |||
user:manage |
x | |||
role:manage |
x | |||
connector:read |
x | |||
connector:manage |
x | |||
audit:read |
x | |||
report:read |
x | x | ||
schedule:read |
x | x | ||
schedule:manage |
x | x |
OIDC Group-to-Role Mapping¶
When OIDC is enabled, Floh requests the openid profile email groups scopes (configurable via OIDC_SCOPE). The IdP is expected to return a groups claim in the ID token or userinfo response. Floh maps those group names to internal roles using environment variables:
| Environment Variable | Floh Role | Example Value |
|---|---|---|
OIDC_ROLE_ADMIN |
admin |
floh-admins |
OIDC_ROLE_APPROVER |
approver |
floh-approvers |
OIDC_ROLE_RESOURCE_MANAGER |
resource_manager |
floh-resource-managers |
OIDC_ROLE_REQUESTOR |
requestor |
floh-requestors |
Each variable accepts a comma-separated list of group names. A user is granted a role if they belong to any of the listed groups. If none of the user's groups match any mapping, they default to the requestor role.
Example .env configuration:
OIDC_SCOPE=openid profile email groups
OIDC_ROLE_ADMIN=floh-admins,platform-admins
OIDC_ROLE_APPROVER=floh-approvers,team-leads
OIDC_ROLE_RESOURCE_MANAGER=floh-resource-managers
OIDC_ROLE_REQUESTOR=floh-requestors,all-staff
A user who belongs to both team-leads and all-staff groups would receive the approver and requestor roles.
External API Access¶
External applications can call Floh APIs by obtaining an access token from the IDP (Authifi or any compliant OIDC/OAuth 2.0 provider).
Prerequisites¶
- Register the Floh resource in your IDP. The resource identifier URI becomes the
audclaim in issued access tokens. Set it viaOIDC_AUDIENCEin Floh's configuration. - Create a client in the IDP for your external application (typically using the
client_credentialsgrant for service-to-service, or the authorization code grant for user-delegated access). - Request a token scoped to the Floh resource identifier.
Calling the API¶
Include the IDP-issued access token in the Authorization header:
Floh validates the token against the IDP's JWKS endpoint, checking:
- Signature — via the IDP's published JSON Web Key Set
- Issuer (iss) — must match OIDC_ISSUER
- Audience (aud) — must match OIDC_AUDIENCE (if configured)
- Expiry (exp) — token must not be expired
Auto-provisioned Users¶
When an API request arrives with a valid IDP token for a sub (subject) that has no account in Floh, a user record is automatically created with the requestor role. An administrator can then assign additional roles via the user management UI or API.
Configuration¶
| Variable | Description | Example |
|---|---|---|
OIDC_ISSUER |
IDP issuer URL | https://a-ci.ncats.io/_api/auth/ls |
OIDC_AUDIENCE |
Resource identifier URI (access token aud) |
https://floh.example.com |
OIDC_CLIENT_ID |
Client ID for the Floh web app's own OIDC flow | floh-client |
Custom Connectors¶
Connector Interface¶
interface ConnectorHandler {
name: string;
version: string;
execute(context: ConnectorContext): Promise<ConnectorResult>;
}
interface ConnectorContext {
config: Record<string, unknown>;
variables: Record<string, unknown>;
stepId: string;
instanceId: string;
}
interface ConnectorResult {
success: boolean;
data?: Record<string, unknown>;
error?: string;
}
Registering a Connector¶
import { registerConnector } from './modules/connectors/registry.js';
registerConnector({
name: 'slack',
version: '1.0.0',
async execute(ctx) {
const { webhookUrl, message } = ctx.config as any;
const resp = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: message }),
});
return { success: resp.ok };
},
});
Built-in Connectors¶
| Name | Description |
|---|---|
http |
Makes HTTP requests to external APIs |
delay |
Pauses execution for a specified duration |
authifi |
Manages Authifi group membership via the Admin API |
To create a new instance of a built-in connector type (e.g. connecting to a second Authifi tenant), use the Connectors → New Connector → Built-in wizard in the UI, or send a POST /api/connectors request with the type set to the registered handler name and executionModel set to built_in. See the Connector Creation Guide for details.
Test Connectors¶
Three simulated connectors are registered automatically and provide realistic seed data for development and testing without external dependencies.
| Name | Description | Default Command |
|---|---|---|
test-ldap |
Simulated LDAP directory with users and groups | search |
test-db |
Simulated relational database with tables | query |
test-activedirectory |
Simulated Active Directory with users, groups, and account management | findUser |
Commands
- test-ldap —
test,search,bind,add,modify,delete - test-db —
test,query,insert,update,delete,list-tables - test-activedirectory —
test,findUser,findGroup,authenticate,getGroupMembers,enableAccount,disableAccount,addToGroup,removeFromGroup,resetPassword,listUsers,listGroups,checkGroupMembership,checkAccountExists,createAccount
Simulating Failures¶
All test connectors accept a simulateFailure config option. When set, the connector returns { success: false } immediately without executing the command. This is useful for testing error-handling paths in workflows.
// Boolean — uses a default error message
{ "connectorName": "test-ldap", "command": "search", "simulateFailure": true }
// → { success: false, error: "Simulated failure (test-ldap connector)" }
// String — uses the value as a custom error message
{ "connectorName": "test-db", "command": "query", "simulateFailure": "Connection refused" }
// → { success: false, error: "Connection refused" }
When simulateFailure is absent, false, or an empty string, the connector executes normally.
Pagination¶
All list endpoints support pagination:
- page — page number (default: 1)
- pageSize — items per page (default: 20, max: 100)
- sortBy — field to sort by
- sortOrder — asc or desc
Response format: