# 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: ```ts 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](/docs/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. ```ts 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 ```sh browserlayer connections create atlas-demo --local --wait browserlayer connections list --local browserlayer connections check --local --wait browserlayer connections reconnect --local --wait ```