# Signing in and secrets

> Sign in with named secrets and reuse browser sign-in state across tests.

Source: https://rehearsal.dev/retest/docs/guides/signing-in

When a flow needs an account, keep its password in a named secret. This guide shows how to use that secret for sign-in and share the resulting browser state across tests.

## Declare a secret

Declare the password source in your config, then refer to it by name in the test. This task-app config reads an environment variable and names the sign-in state you will save.

```ts filename="retest.config.ts"
import { chrome, defineConfig, env } from '@rehearsal-labs/retest'

const config = defineConfig({
  apps: { web: chrome({ baseUrl: 'http://127.0.0.1:4173' }) },
  secrets: { password: env('TASK_APP_PASSWORD') },
  states: ['signed-in'],
})

export default config

declare module '@rehearsal-labs/retest' {
  interface Register {
    config: typeof config
  }
}
```

Set `TASK_APP_PASSWORD` in the environment where you run Retest. An `env()` source is read once when the run starts; a missing value or one shorter than four characters stops the run with exit code 2.

`secret('password')` gives the test a handle that prints as `{{password}}`. Retest types the password from its own process and removes the source variable from the test process's environment, so the test receives no value.

## Sign in once

Use `test.setup()` to sign in through the page. When the setup passes, Retest saves its browser state, so check that sign-in succeeded before the setup returns.

```ts filename="tests/sign-in.retest.ts"
import { expect, secret, test } from '@rehearsal-labs/retest'

test.setup('signed-in', async ({ page }) => {
  await page.goto('/login')
  await page.getByLabel('User name').fill('alice')
  await page.getByLabel('Password').fill(secret('password'))
  await page.getByRole('button', { name: 'Sign in' }).click()
  await expect(page.getByTestId('account')).toHaveText('Signed in as alice')
})

test('saves a task while signed in', { state: 'signed-in' }, async ({ page }) => {
  await page.goto('/')
  await page.getByTestId('task-title').fill('Release checklist')
  await page.getByTestId('save-task').click()
  await expect(page.getByTestId('saved-task')).toHaveText('Release checklist')
})
```

The setup runs once for each browser target that needs it. Each dependent test gets a new browser context with the saved cookies and `localStorage`, then opens its own page with `goto()`.

Declare setups at the top level of a file, with one app and a unique state name. When you select a test file without its setup, Retest searches the other `.retest.ts` files under the root for the setup it needs.

If the setup fails, its dependent tests are `not_run` and show that failure as their reason. A state name with no matching setup is a collection error, so check the spelling and app in both declarations.

> [!NOTE]
> **What the state holds**
>
> Saved state holds cookies and `localStorage`, but no `sessionStorage` or server data. Retest keeps it under the run folder's `states/` directory and removes it during cleanup; a forced kill can leave it behind.

## Allow another origin

On a browser page, a secret may be typed on the origins of the test's apps' base URLs. If sign-in takes you to another site, add that site's origin beside `secrets` in the config.

```ts filename="retest.config.ts"
defineConfig({
  // Keep your apps, secrets and states here.
  secretOrigins: { password: ['https://login.tasks.example'] },
})
```

Retest checks the destination before reading the secret and again before typing it. A fill on an origin outside this list fails with `not_actionable` and sends no text; check the destination before adding it.

In an Electron window, only the origins explicitly listed in `secretOrigins` count, and a `file://` page cannot receive a secret. For an iOS simulator or macOS app, list its exact bundle identifier instead of a web origin.

## Redaction and platform limits

Retest replaces known secret values with their placeholders in recorded text and in page text returned to the test. Check the result of signing in, such as the account label, rather than trying to read the password back.

A secret source can also be a function, called for each fill with an abort signal. If it throws or returns invalid text, the fill fails with `setup_failed`; see [Configuration options](https://rehearsal.dev/retest/docs/reference/config.md) for the source contract.

> [!WARNING]
> **Pixels can show a secret**
>
> Screenshots and recordings are not redacted. A password your app displays can appear in them, even when recorded text is hidden. See [Recordings and evidence](https://rehearsal.dev/retest/docs/guides/recordings-and-evidence.md) for the capture rules.

Browser sign-in state works on Chromium-family browsers, Firefox and WebKit. `test.setup()` cannot save or restore Electron or native app state. For persistent app data, see [Electron apps](https://rehearsal.dev/retest/docs/platforms/electron.md), [iOS simulator apps](https://rehearsal.dev/retest/docs/platforms/ios.md) or [macOS apps](https://rehearsal.dev/retest/docs/platforms/macos.md).

## Next steps

- [Email codes and links](https://rehearsal.dev/retest/docs/guides/email-codes-and-links.md): Complete sign-in with a message from a test inbox.
- [Configuration options](https://rehearsal.dev/retest/docs/reference/config.md): Look up secret sources, origins and state settings.
- [One test across platforms](https://rehearsal.dev/retest/docs/platforms/across-platforms.md): Give each participant its own app and account.
