Use credentials for scripted login, auth profiles for saved browser state, and librettoAuthenticate to recover when a saved session is missing or expired.
Libretto supports two website authentication tools:
credentials are secrets such as usernames, passwords, API keys, and TOTP shared secrets. Use them when the workflow can log in with Playwright.
authProfile is named browser state for a signed-in session. Use it when a workflow should start from an existing login or preserve login state across runs.
By default, Libretto-generated login workflows combine both: the workflow starts with the named auth profile, checks whether it is signed in, and signs in with credentials when the profile is missing, expired, or logged out.
import { librettoAuthenticate, workflow } from "libretto";
import { z } from "zod";
export default workflow("portalReport", {
credentials: ["username", "password"],
authProfile: {
name: "portal",
refresh: true,
},
input: z.object({
reportId: z.string(),
}),
output: z.object({
title: z.string(),
}),
async handler(ctx, input) {
const { page } = ctx;
await page.goto("https://portal.example.com");
await librettoAuthenticate(ctx, {
credentials: input.credentials,
isSignedIn: async ({ page }) =>
await page
.getByRole("button", { name: /account|sign out/i })
.isVisible()
.catch(() => false),
signIn: async ({ page }, credentials) => {
await page.goto("https://portal.example.com/login");
await page.getByLabel("Email").fill(credentials.username);
await page.getByLabel("Password").fill(credentials.password);
await page.getByRole("button", { name: /log in/i }).click();
},
});
await page.goto(`https://portal.example.com/reports/${input.reportId}`);
const title = await page.locator("h1").innerText();
return { title };
},
});
In this pattern, the auth profile handles the common case where the browser is already signed in. The signIn step handles the recovery case where the profile is missing, expired, or logged out. If sign-in succeeds and refresh: true is set, the run saves the updated browser state back to the profile for future runs.
Credentials
Credentials are separate from normal workflow input. Declare the names the workflow needs, then read the resolved values from input.credentials. Do not pass secrets through --params.
For local runs, store matching variables in .env:
LIBRETTO_CLOUD_USERNAME=alice@example.com
LIBRETTO_CLOUD_PASSWORD=secret
LIBRETTO_CLOUD_TOTP_SECRET=JBSWY3DPEHPK3PXP
Libretto removes the LIBRETTO_CLOUD_ prefix and lowercases the rest, so LIBRETTO_CLOUD_USERNAME becomes input.credentials.username.
For hosted runs, store the same credential names in Libretto Cloud. See Libretto Cloud credentials.
Never put secrets in workflow params, logs, or source code. Use declared credentials backed by .env locally and Libretto Cloud credentials in hosted runs.
Auth profiles
An auth profile is named browser state for a login session. Local profiles live in .libretto/profiles/<name>.json; hosted profiles are provider-native browser profiles managed by Libretto Cloud and the active browser provider.
Use the workflow-level authProfile option:
authProfile: "portal"
authProfile: {
name: "portal",
refresh: true,
}
Use { name, refresh: true } when successful runs should persist updated browser state back to the profile. On local runs, this updates the local .libretto/profiles/<name>.json file. On hosted runs, it asks the browser provider to persist changes to the provider-native profile.
The preferred way to create a local profile is to sign in through a headed Libretto session and save it:
npx libretto open https://portal.example.com --headed --session portal-login
# Log in manually in the browser window.
npx libretto save portal --session portal-login --sites portal.example.com
Use this when the login cannot be scripted with Playwright, such as CAPTCHAs, SMS codes, device approvals, or magic links. Once saved, the workflow can use authProfile: "portal" or authProfile: { name: "portal", refresh: true } without repeating the manual login every run.
If you already have a signed-in Chrome profile and explicitly want to copy from it, start that Chrome profile with remote debugging enabled and import only the sites you need:
npx libretto import-chrome-profiles portal --cdp-url http://127.0.0.1:9222 --sites portal.example.com
Chrome often needs to be closed and relaunched with a temporary user-data directory before remote debugging can attach. Importing from Chrome can close or relaunch that browser window, so confirm with the user before doing it.
Use --sites only when saving or importing a local profile. It controls which site storage is copied into the local profile. See CLI profiles.
Hosted website authentication
Hosted runs do not upload local .libretto/profiles/<name>.json files. They use provider-native profiles with the workflow’s authProfile.name. libretto cloud deploy registers missing profile names, and hosted runs populate or refresh the provider profile when sign-in succeeds.
For the hosted model, provider behavior, and profile persistence details, see Website authentication in Libretto Cloud.
Runtime helper
Use librettoAuthenticate when a workflow has an auth profile and scripted sign-in. The helper runs your isSignedIn check, calls your signIn function if needed, and checks again before the workflow continues.