> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revyl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth and session prep

> How session.before_script and session.auth_bypass attach when you run revyl device start

When `.revyl/config.yaml` declares `session.before_script` and/or
`session.auth_bypass`, `revyl device start` (and `revyl dev`) run the
before-script and apply mobile auth-bypass settings automatically for iOS and
Android sessions. Web sessions use `session.auth_bypass.sign_in` instead. You
do not pass tokens on the command line.

For the app-side deep-link contract and mint-script shape, see
[Auth Bypass Deep Links](/devices/auth-bypass). This page covers what
the CLI does on device start.

## Web Sign-In Links

<Note>
  Web is in alpha. To add it to your organization, email [support@revyl.ai](mailto:support@revyl.ai).
</Note>

For a web app with a test-only sign-in route, configure a worker-minted link:

```yaml
session:
  auth_bypass:
    sign_in:
      path: /revyl-login
      secret: REVYL_SIGN_IN_SECRET
```

`secret` names a secret key-value launch variable in your organization, not its
value. The CLI and MCP send only the name; the trusted worker reads the bound
variable and opens `<build-origin><path>?code=…` before handing over
the session. Web starts do not run `session.before_script` or the mobile
launch-variable or deep-link preparation pipeline. Use
`session.auth_bypass.sign_in` for Web sign-in; any data a Web proof needs must
already exist in the preview environment, for example seeded by the preview's
own deploy or a test-login route.

A pull request comment's Open preview link signs its Web preview in with
the project's published `sign_in`, as mobile previews apply
`auth_bypass`; the pull request's own config cannot change it.

For Next.js App Router and static Vite examples, see the
[manual Web setup guide](https://github.com/RevylAI/revyl-cli/blob/main/skills/revyl-cli-auth-bypass/references/web.md).

`path` must start with a single `/` and cannot contain a query, fragment,
backslash, or whitespace. It is limited to 512 characters. Every code expires
after 120 seconds. The app's sign-in handler chooses the destination after exchanging
the code; Revyl does not send a redirect parameter.

The code is an HS256 compact JWS signed with the UTF-8 secret. The app must
verify its signature, `iss: "revyl"`, `aud` matching the lowercase build origin
without a default port, `sub: "default"`, and integer `iat` and
`exp: iat + 120` timestamps. It must consume each `jti` (16 random bytes encoded
as unpadded base64url) only once, then exchange the code for its own session.

The worker waits up to 30 seconds to leave the sign-in path on the same origin;
otherwise startup fails with `sign_in_failed`. The secret and code are not
included in workflow inputs or reports, and recording starts after the
redirect. Session metadata retains only the selected variable ID to authorize
the worker's secret read.

The config block is accepted in shared project configuration, but only Web
sessions act on it. Existing mobile behavior below is unchanged.

### Per-session environment overrides

A managed Web session can replace or add to its app's environment for that
session only, for example to point the app at a pull request's backend behind a
public tunnel. Pass each value with `--launch-env`, the same flag mobile starts
use, and no configuration change is needed:

```bash
revyl device start --platform web \
  --launch-env BACKEND_URL=https://pr-123.example.dev \
  --launch-env REVYL_SIGN_IN_SECRET
```

`--launch-env KEY=VALUE` is a plain override. `--launch-env NAME` with no `=`
is a secret override: the CLI reads its value from the local environment
variable `NAME`, so the value is never a command argument, never printed, and
never written to session metadata. MCP `launch_env` takes plain values only,
because a secret value would pass through the agent's tool arguments.

An override replaces the organization's value for one of the run's `env_keys`
or adds a new variable to the app process. Names must match
`[A-Za-z_][A-Za-z0-9_]{0,127}`. A session takes at most 32 overrides, each
value is at most 4,096 bytes with no control characters, and names plus values
together stay within the runtime's 128 KiB environment limit. A pull request
preview start (`scm_preview_id`) takes no overrides. The runtime owns
`PATH`, `HOME`, `LANG`, `PORT`, `HOSTNAME`, and `WEB_APP_BOOTSTRAP`, and
names starting with `DYLD_`, `SIMCTL_CHILD_`, or `COGNISIM_` are reserved, so
overrides can't use them. A plain override can't use a name in the run's
`secret_names` or an encrypted organization launch variable; pass those as
secret overrides.

A session with any override gets none of the organization's secrets: no
`secret_names` values and no organization sign-in secret. Secret overrides
reach the app process as its secrets instead. If one is named by
`session.auth_bypass.sign_in.secret`, it becomes the session's sign-in secret:
the worker signs the sign-in code with it, and it never enters the app's
environment. That name can't be a plain override. Without it, sign-in is off for
that session. Revyl stores override values encrypted for the session only and
deletes them when the session ends. Sessions without overrides are unchanged,
and overrides need a managed Web bundle. The session report lists each
overridden name, marks secret ones, and shows only the host of plain values that
parse as URLs.

## Mobile Attach Order On `revyl device start`

iOS and Android starts use this pipeline:

1. **Read optional session settings** from the nearest `.revyl/config.yaml`
   within the current Git worktree, or from the current directory outside Git.
   No config means command defaults and explicit flags. Legacy
   `defaults.timeout`, `before_session`, and `auth_bypass` settings work without
   migration; unrelated build and PR-review settings do not block device start.
   Malformed YAML and invalid session settings still fail before provisioning.
2. **Run `session.before_script`** (if configured). The script must finish before the
   device boots. `KEY=VALUE` lines on stdout become **session-scoped** launch
   environment for this start only. A non-zero exit aborts start — Revyl will
   not boot an unprepared app.
3. **Apply `session.auth_bypass.launch_vars`**. The CLI adds the configured org
   launch-variable keys to the explicit and inherited keys selected for this start. Keys that
   the before script already printed as inline values are not also looked up
   in org state.
4. **Boot the device** with that launch environment fixed for the session.
   For iOS, selected `--launch-arg-set` values are flattened in flag order and
   inline `--launch-arg` tokens are appended. These explicit tokens are placed
   before legacy `-KEY value` pairs. Android rejects explicit arguments.
5. **Fire `session.auth_bypass.deep_link`** (if configured and you did not pass
   `--app-link`). Placeholder substitution must use either only
   before-script values or only org launch variables — never a mix.

```mermaid
flowchart TD
  A["revyl device start"] --> B["Read optional session settings"]
  B --> C{"session.before_script configured?"}
  C -->|yes| D["Run script → KEY=VALUE"]
  C -->|no| E["Skip mint"]
  D --> F["Merge launch env + session.auth_bypass.launch_vars"]
  E --> F
  F --> G["Boot device / install build"]
  G --> H{"session.auth_bypass.deep_link?"}
  H -->|yes| I["Open deep link"]
  H -->|no| J["Session ready"]
  I --> J
```

## Config Reminder

Both settings live under the `session` section:

```yaml
session:
  before_script:
    script_path: "./scripts/prepare-test-session.sh"
    timeout_seconds: 120
  auth_bypass:
    launch_vars: [REVYL_AUTH_BYPASS_ENABLED, REVYL_AUTH_BYPASS_TOKEN]
    deep_link: "myapp://revyl-auth?token=${REVYL_AUTH_BYPASS_TOKEN}"
```

One produces values; the other consumes them. Full script contract:
[Mint The Token Per Session](/devices/auth-bypass#mint-the-token-per-session).

## Working Directory Matters

Inside Git, config is found by walking **up** from your cwd to the nearest
`.revyl/config.yaml`, stopping at the worktree root. Outside Git, only the
current directory is checked. Use `-C <project-dir>` to choose the directory.
In a monorepo where the Revyl project lives in a subdirectory
(for example `ios/.revyl/config.yaml`), run device commands from that
project directory (or below it):

```bash
cd ios
revyl device start --platform ios --build-version-id <id> --json
```

If you start from the monorepo root and there is no root-level `.revyl/`,
the CLI will not load the nested config — `session.before_script` and
`session.auth_bypass`
are skipped silently.

## Overrides And Precedence

| Source                                             | Role                                                                 |
| -------------------------------------------------- | -------------------------------------------------------------------- |
| `session.before_script` stdout                     | Session-scoped launch env                                            |
| `--launch-env KEY=VALUE`                           | Wins over minted and org values for the same key                     |
| `session.auth_bypass.launch_vars` / `--launch-var` | Org launch-variable keys attached at boot                            |
| `--launch-arg-set <name-or-id>`                    | Stored ordered iOS argument sets, flattened in flag order            |
| `--launch-arg=<token>`                             | Exact inline iOS token appended after stored sets; always non-secret |
| `session.auth_bypass.deep_link`                    | Post-launch navigate (after boot)                                    |

Launch environment is fixed at boot. `revyl dev auth refresh` re-fires the
deep link with the **same** boot values; it does not remint. If the token
expired, stop and start again so the before script runs fresh.

## What Does Not Run `session.before_script`

The PR **preview link** in a GitHub comment has no checkout, so it cannot run
your mint script. That path still uses organization launch variables only.
Keep org vars fresh if reviewers rely on the preview link being signed in;
mobile proof agents and local mobile `revyl device start` use the before script
instead. Web starts do not run it; prepare any test data explicitly before Start.

## Verify

```bash
# From the directory that owns .revyl/
revyl device start --platform ios --timeout 1800 --json
# Confirm the app is signed in (screenshot / validation), then:
revyl device stop
```

`revyl dev status` reports the runtime `before_session` key **names** and state only —
never token values.
