Integration

Integration Quickstart

The exact requests — methods, headers, and JSON bodies — behind every step of integrating secureFlows. This is the technical companion to the Integration Walkthrough, which explains what each step is for and why; this page shows the wire format so you can wire it up directly.

On this page

  1. Terminology
  2. Flow A — Provisioning
  3. Flow B — Runtime auth
  4. Session API reference
  5. Flow C — Invite activation
  6. Automation (n8n / Make / Zapier)
  7. Verify your integration
  8. API reference

Terminology

TermMeaning
WorkspaceTenant boundary — users, applications, and session policy.
ApplicationA client integration inside a workspace (appId, redirect URIs).
ConsoleThe Workspace Management UI at /app for owners/admins.
Hosted session login/app/sessions/login — returns a sessionToken on your /callback.

One workspace can hold many applications.

AProvisioning (owner/admin, once)

A1 — Owner signs in

Open the console and sign in with Firebase (email/password or a configured provider):

GET /app

A2 — Create a workspace

POST /api/v1/workspaces

HeaderValue
AuthorizationBearer <firebase-id-token>
Content-Typeapplication/json
{
  "name": "acme-main",
  "acceptAnonimous": true,
  "enableSelfService": true
}
FieldDefaultMeaning
acceptAnonimoustrueOpen signup vs. invite-only (POST /users/anonymous and anonymous session creation).
enableSelfServicetrueWhether end users may use /app/self and the self-service API routes.

Both can be changed later via PATCH /api/v1/workspaces with an OWNER/ADMIN token.

The response includes workspace (the created tenant) and accessToken (an internal OWNER user JWT for the Management API).

A3 — Register an application

Using the owner/admin token from A2:

POST /api/v1/applications

{
  "appId": "acme-web",
  "displayName": "Acme Web App",
  "redirectUris": [
    "https://app.acme.com/auth/callback"
  ]
}

The appId value is what you pass as app_id on hosted login URLs.

BRuntime auth (end users, session token)

Use this for client apps on any host, including AI builder previews such as Base44 or Lovable.

B1 — Open hosted session login

Redirect or link the user to:

GET /app/sessions/login?workspace_name=<workspace>&app_id=<application-id>&redirect_uri=<url-encoded-callback>&state=<opaque>

Example:

https://www.secure-flows.com/app/sessions/login?workspace_name=demo-workspace&app_id=acme-web&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fcallback&state=abc123

Allowlist redirect_uri in the dashboard first — the exact URL, including /callback.

B2 — User signs in

The user completes sign-in in the hosted UI. If the browser is already signed in (from a previous visit, or another secureFlows-hosted app), they are not signed in silently — hosted login shows an account-confirmation prompt (“Continue as <email> to <your app’s display name>?”) with the option to use a different account. Set a clear display name for your application in the dashboard; it is what users see on that prompt.

B3 — Server creates a session and redirects to your app

The browser lands on your allowlisted redirect_uri with:

Query paramPurpose
sessionTokenSession JWT — store in sessionStorage, send as Authorization: Bearer ….
stateThe same value you sent (CSRF binding; optional on some platforms).
https://app.acme.com/callback?sessionToken=<jwt>&state=abc123

B4 — Use the Session API

GET /api/v1/sessions with Authorization: Bearer <sessionToken> reads and writes the flat JSON payload; see the full reference below.

401 / 410 is not data loss

Call hosted login again with session_token=<expired> to renew — the underlying session and its data are untouched.

Session API reference

Every call below needs Authorization: Bearer <sessionToken>. Never send userId, workspaceId, or any other identity field in the body — identity is always resolved from the token.

Read everything

GET /api/v1/sessions

// 200 — flat object, one entry per key. Empty session returns {}.
{
  "note:shopping": "Milk, eggs, bread",
  "theme": "dark"
}

Read one key

GET /api/v1/sessions/get/<key>

// 200
{ "key": "note:shopping", "value": "Milk, eggs, bread" }

Read the value as response.value. A 404 means the key has never been written — return a default, do not throw.

Write a key

POST /api/v1/sessions/set/<key>

{ "value": "Milk, eggs, bread, butter" }

The value can be any JSON type — string, number, boolean, array, or object. The response is the same flat object shape as GET /sessions, already updated.

Delete a key

DELETE /api/v1/sessions/delete/<key>

// 200 — true if the key existed and was deleted, false otherwise
true

Read the signed-in user’s email

GET /api/v1/sessions/identity

// 200
{ "email": "[email protected]" }
// or, if the client is anonymous:
{ "email": null }

With secureflows-js (≥ 0.1.13): await sf.fetchSessionIdentity(token). Use this instead of decoding the JWT yourself.

Revoke the session

POST /api/v1/sessions/revoke

// 200
{ "revoked": true, "sessionId": 123 }

After revoking, clear the token from memory and redirect to hosted login. Do not reuse the token — any further request with it returns 410.

CInvite activation (workspace member, once per invite)

Admins create invites in the console (Workspace → Invites) and share the activation URL with the joiner.

C1 — Open the activation link

GET /app/accept-invite?key=<invite-secret>

This is not hosted login — there is no app_id or redirect_uri.

C2 — Sign in and activate

Sign in with Firebase in the hosted UI, then:

POST /api/v1/users/from-invite

{ "secretKey": "<invite-secret>" }

Header: Authorization: Bearer <firebase-id-token>. On success, the user is created in the workspace with the invite’s role.

Automation (n8n / Make / Zapier)

Treat Flow A as one-time admin setup. Flow B is designed for human sign-in; automation typically needs a different credential strategy — define your threat model before embedding a Firebase login inside a workflow.

Verify your integration

API reference