Authentication
Browserlayer calls two reserved connector flows. Your app opens Link instead of invoking them as endpoints.
| File | Role | Output schema |
|---|---|---|
connector/flows/authenticate.ts | Establish a connection; collect credentials and MFA | connectionResult |
connector/flows/reauthenticate.ts | Reuse the session or restore it | connectionCheckResult |
Authenticate
connector/flows/authenticate.ts — minimal website-specific example:
import { createFlow, connectionResult, form } from "@browserlayer/sdk";
import { z } from "zod";
const credentials = form(
z.object({ email: z.email(), password: z.string().min(1) }),
{
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
);
export default createFlow({
description: "Sign in to the website.",
input: z.object({}),
output: connectionResult,
initialInput: { id: "credentials", form: credentials },
async exec(ctx) {
await ctx.step("open", async () => {
await (await ctx.browser()).goto("https://example.com/login");
});
const values = await ctx.input("credentials", credentials);
await ctx.step("sign-in", async () => {
const page = await ctx.browser();
await page.getByLabel("Email").fill(values.email);
await page.getByLabel("Password").fill(values.password);
await page.getByRole("button", { name: "Sign in" }).click();
await page.getByRole("heading", { name: "Your account" }).waitFor();
await ctx.connection!.data.set("credentials", values);
});
return { authenticated: true as const };
},
});Replace the URL and selectors using your capture. For an executable login with MFA, use Atlas.
Reauthenticate
Check the retained session first. If expired, call authentication or restore it with saved connection data. Reauthentication may request input and resume within the current run.
import { createFlow, connectionCheckResult } from "@browserlayer/sdk";
import { z } from "zod";
import authenticate from "./authenticate.js";
export default createFlow({
description: "Restore the account session when needed.",
connection: "required",
input: z.object({}),
output: connectionCheckResult,
async exec(ctx) {
const connected = await ctx.step("check-session", async () => {
const page = await ctx.browser();
return page.getByRole("heading", { name: "Your account" }).isVisible();
});
if (!connected) await ctx.run(authenticate, {});
return { status: "connected" as const };
},
});Returning { status: "requires_input", reason: "verification_required" } instead of requesting input fails the business run with CONNECTION_REQUIRES_INPUT. The app must reconnect and invoke again. Use inline input when you want the original run to continue.
Test a connection
browserlayer connections create atlas-demo --local --wait
browserlayer connections list --local
browserlayer connections check <connection-id> --local --wait
browserlayer connections reconnect <connection-id> --local --wait