AppsGuide

Login by a flow

Waiso keeps no passwords for your app’s visitors. A login flow you write checks what the visitor typed — against a table, a list, an invite code — and answers {"user": {...}} to let them in.

What you will learn
  • Mark a flow as an app’s login
  • Sign a visitor in from the page
  • Make an endpoint answer only signed-in visitors and receive who they are

How it works

Three pieces meet: the app (a page with a sign-in form), the login flow (your rules for who gets in) and the endpoints the signed-in page calls. The page sends what the visitor typed to the app’s login; Waiso runs your flow; when the flow answers a user, Waiso hands the page a session that lasts as long as the app’s settings say. From then on every call carries it, and endpoints set to App users accept only calls that do.

Endpoints PrivateOnly scripts that have been published from the editor appear here.
Settings
Search endpoints…Ctrl KAll 8Active 3Inactive 5All typesScriptsFlowsScraper
hello/helloMethodPOSTModeSyncAuthBearerStatus
report/daily-reportMethodPOSTModeAsyncAuthBearerStatus
campaign/campaignMethodPOSTModeAsyncAuthBearerStatus
greetNot configuredMethod—Mode—Auth—Status
counterNot configuredMethod—Mode—Auth—Status
approvalNot configuredMethod—Mode—Auth—Status
The API page, where each endpoint’s access is chosen: an API token, public, or App users.

The user your flow returns is yours to shape — an id, a name, a role, the client account a visitor belongs to. Whatever it holds is exactly what each App users endpoint receives, so a script can filter a table by user["id"] without ever trusting what the page sends.

Set it up

  1. Write the login flow

    A flow whose last step answers {"user": {...}} to let someone in, or anything else (a message is shown) to refuse. Publish it.

  2. Pick it in the app

    App → Settings → Login: choose the flow and how long a session lasts (7 days by default).

  3. Protect the endpoints

    On the API page, set each private endpoint’s access to App users.

Pythoncheck-guest.py
def main(email: str = "", code: str = ""):
    # Decide who gets in: a table, a list, an invite code — your rules.
    guests = {"ana@exemplo.com": "1234"}
    if guests.get(email.strip().lower()) == code:
        return {"user": {"email": email, "name": email.split("@")[0]}}
    return {"message": "Wrong e-mail or code"}

From the page

htmllogin.html
<script src="/_waiso.js"></script>
<script>
  async function signIn(email, code) {
    try {
      const user = await waiso.login({ email, code })   // runs the login flow
      show(`Hello, ${user.name}`)
    } catch (e) {
      show(e.body?.message || 'Could not sign in')
    }
  }
  // Every call now carries the session; "App users" endpoints receive `user`.
  const mine = await waiso.call('my-orders', {})
</script>

The session is kept for the open tab only and sent in a header on each call — never a cookie — so it works the same on a downloaded copy. waiso.logout() ends it; Sign everyone out in Settings ends them all.

What an App users endpoint receives

Pythonmy-orders.py
def main(user: dict):
    # Only signed-in visitors reach this; user is what the login flow returned.
    return {"orders": find_orders(user["email"])}
  • A flow receives user as an input; a script when it declares a user parameter.
  • No session, an expired one, or one of another project’s app: refused with 401 before anything runs.
  • Login attempts are slowed after 10 a minute per visitor.

In Runs

The login flow’s runs are yours, like any run — what the visitor typed is in their inputs, so check codes rather than store real passwords in it.

A session belongs to one app and one project: a session from another project’s app is refused everywhere here, and signing everyone out of one app never touches another. When an app is taken down, its sessions stop working at once.

Keep the session short for sensitive pages: an hour is enough for a back-office form, a week suits a guest list.