Skip to content

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 enabled
  • GET /api/auth/login — redirect to OIDC login
  • GET /api/auth/callback — OIDC callback (handles code exchange)
  • GET /api/auth/me — current user info
  • POST /api/auth/logout — logout

Workflows

  • GET /api/workflows — list definitions (paginated)
  • POST /api/workflows — create definition
  • GET /api/workflows/:id — get definition
  • PUT /api/workflows/:id — update definition (draft only)
  • POST /api/workflows/:id/publish — publish (draft → active)
  • POST /api/workflows/:id/start — start run
  • DELETE /api/workflows/:id — delete definition

Runs

  • GET /api/runs — list runs (paginated, filterable by status, definitionId)
  • GET /api/runs/:id — get run
  • PUT /api/runs/:id — edit run variables (pending/running only)
  • POST /api/runs/:id/cancel — cancel run

Tasks & Approvals

  • GET /api/tasks — list assigned tasks
  • POST /api/tasks/:id/complete — complete task
  • GET /api/approvals — list pending approvals
  • POST /api/approvals/:id/decide — approve/reject

Other

  • GET /api/users, PATCH /api/users/:id/roles
  • GET /api/connectors, POST /api/connectors, POST /api/connectors/:id/test
  • GET /api/schedules, POST /api/schedules, PATCH /api/schedules/:id
  • GET /api/audit-logs — with filters
  • GET /api/reports/* — workflow-stats, sla-compliance, approver-performance
  • GET /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

  1. Register the Floh resource in your IDP. The resource identifier URI becomes the aud claim in issued access tokens. Set it via OIDC_AUDIENCE in Floh's configuration.
  2. Create a client in the IDP for your external application (typically using the client_credentials grant for service-to-service, or the authorization code grant for user-delegated access).
  3. Request a token scoped to the Floh resource identifier.

Calling the API

Include the IDP-issued access token in the Authorization header:

curl -H "Authorization: Bearer <access_token>" \
  https://floh.example.com/api/workflows

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-ldaptest, search, bind, add, modify, delete
  • test-dbtest, query, insert, update, delete, list-tables
  • test-activedirectorytest, 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 - sortOrderasc or desc

Response format:

{
  "data": [...],
  "total": 100,
  "page": 1,
  "pageSize": 20,
  "totalPages": 5
}