# secureFlows integration quickstart

This doc describes the correct end-to-end flow without circular dependencies by separating:

- **Provisioning (owner/admin, done once)**: create a workspace and register an application.
- **Runtime auth (end-users, ongoing)**: your application sends users to hosted SafeHook login.

## Terminology

- **Workspace**: a tenant boundary (users/data/permissions).
- **Application**: a client integration *inside* a workspace (web app, mobile app, automation connector).
- **Console**: SafeHook UI for owners/admins (no `app_id` required).
- **Hosted Login**: SafeHook UI used by end-users coming from a client app (requires `app_id` on the login URL).

Relationship: **one Workspace → many Applications**.

## Flow A: Provisioning (owner/admin, once)

### A1) Owner signs in (Firebase)

Open the Console and sign in:

- `GET /app` (then “Sign in”)

### A2) Owner creates a workspace (Firebase token only)

Call:

- `POST /api/v1/workspaces`

Headers:

- `Authorization: Bearer <firebase-id-token>`
- `Content-Type: application/json`

Body:

```json
{
  "name": "acme-main",
  "acceptAnonimous": true
}
```

Response:

- `workspace`: created workspace object
- `accessToken`: privileged internal **OWNER** user token for this workspace

### A3) Owner registers an application under the workspace

Use the OWNER/ADMIN token from A2:

- `POST /api/v1/applications`

Headers:

- `Authorization: Bearer <owner-user-token>`
- `Content-Type: application/json`

Body:

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

The JSON field is `appId` (same value you pass as `app_id` in hosted login). Result: you can embed this id in your app configuration.

## Flow C: Self-service invite (workspace member, once per invite)

Admins create **invites** in the Console (**Workspace → Invites**). Each invite has a secret key. Share the **activation URL** with the person joining the workspace (not the admin UI).

### C1) Open the activation link

Hosted SafeHook URL (path may be under your deployment prefix):

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

Example:

`https://your-secureflows-host/app/accept-invite?key=<uuid-or-secret>`

This route is **not** the integration hosted-login URL (`app_id` / `redirect_uri`). It is for humans accepting a workspace invite in the browser.

### C2) Sign in and activate

1. Sign in with Firebase (email/password in the hosted UI).
2. Call activation with the same invite secret:

- `POST /api/v1/users/from-invite`

Headers:

- `Authorization: Bearer <firebase-id-token>`
- `Content-Type: application/json`

Body:

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

Success: user is created in the workspace with the role defined on the invite. **USER** role typically stays on the success screen; **ADMIN** may be redirected to Workspace Management depending on product behavior.

## Flow B: Runtime auth (end-users, ongoing)

### B1) Your app opens hosted SafeHook login

Send the user to:

- `GET /app/login?app_id=<application-id>&redirect_uri=<your-callback-url>&state=<opaque-value>`

Example:

`https://your-secureflows-host/app/login?app_id=acme-web&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fauth%2Fcallback&state=abc123`

(`app_id` matches the `appId` you registered in Flow A. The legacy query name `client_id` is still accepted for older links.)

SafeHook validates:

- `app_id` refers to a registered application
- `redirect_uri` is allowlisted for that application

### B2) User signs in (Firebase)

User completes email/google sign-in in hosted UI.

### B3) Your app receives the result

After the user signs in successfully, SafeHook validates `app_id` and `redirect_uri` with the backend, then **redirects the browser** to your allowlisted `redirect_uri`.

Query parameters on the redirect:

- `firebaseToken`: Firebase ID token for the signed-in user
- `state`: the same `state` value you passed on the login URL (echo back for CSRF protection)

Example final URL:

`https://app.acme.com/auth/callback?firebaseToken=<jwt>&state=abc123`

This works whether the user opened hosted login in a **normal tab** or a **popup**; your callback page should read the query string and establish a session.

`redirect_uri` must match an entry in the application’s `redirectUris` (from Flow A). Local development URLs must be registered exactly (for example `http://localhost:3000/auth/callback`).

> Phase 3 may replace “token in query” with an auth-code exchange flow.

## n8n / Make / Zapier note

For automation tooling, treat Provisioning (Flow A) as a one-time admin setup step.
Runtime auth (Flow B) is typically replaced by a service-to-service credential strategy or a
future auth-code flow depending on your threat model.
