# Croc's Password Relay Authentication Mechanism Using the --pass Flag

> Learn how Croc's password relay authentication ensures secure transfers. Discover how the --pass flag validates custom passwords during the TCP handshake for authenticated access.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: deep-dive
- Published: 2026-07-26

---

**Croc's password relay authentication mechanism validates custom passwords during the TCP handshake by passing the `--pass` flag value through the **determinePass** function in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go) to **tcp.ConnectToTCPServer** in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), ensuring only authenticated clients can join the transfer room.**

The `schollz/croc` tool enables secure cross-platform file transfers using relay servers to bridge network gaps. When operating a private relay or requiring additional access control beyond the default passphrase, Croc's password relay authentication mechanism allows users to specify a custom credential using the **--pass** command-line flag or the **CROC_PASS** environment variable.

## Parsing the Password in the CLI Layer

The authentication flow begins in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go), where the **determinePass** helper function extracts the password from user input. This function checks for the explicit `--pass` flag first, then falls back to the `CROC_PASS` environment variable, and finally defaults to the standard passphrase if neither is provided.

```go
// src/cli/cli.go (approximate line 379)
RelayPassword: determinePass(c),

```

The implementation sanitizes the input by trimming whitespace and assigns the result to the **Options.RelayPassword** field. This field is defined in [`src/models/options.go`](https://github.com/schollz/croc/blob/main/src/models/options.go) alongside the **DEFAULT_PASSPHRASE** constant, which the system uses as a baseline for comparison.

## Propagating the Password to the Transfer Command

Once parsed, the password flows into the core client logic in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). When generating the command string that receivers must execute, the code explicitly checks whether **Options.RelayPassword** differs from **models.DEFAULT_PASSPHRASE**. If a custom value is detected, it appends the flag to the generated command using a **strings.Builder**.

```go
// src/croc/croc.go (lines 1345-1347)
if c.Options.RelayPassword != models.DEFAULT_PASSPHRASE {
    flags.WriteString("--pass " + c.Options.RelayPassword + " ")
}

```

This constructed command is printed to standard error and copied to the system clipboard, ensuring the receiver receives the exact authentication credential required to access the transfer.

## Authenticating with the Relay Server

The actual authentication occurs during the TCP handshake. In [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), the client invokes **tcp.ConnectToTCPServer** and passes **Options.RelayPassword** as the second argument. This function transmits the credential to the relay server for validation before establishing the encrypted data channel.

```go
// src/croc/croc.go (lines 1410-1412)
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(
    address, 
    c.Options.RelayPassword, 
    c.Options.RoomName, 
    durations[i],
)

```

If the relay rejects the password, the connection attempt fails immediately with an authentication error. This prevents unauthorized clients from joining the room even if they possess the correct room code.

## Practical Usage Examples

### Sending Files with a Custom Password

To protect a file transfer with a specific credential, include the flag when invoking the send command:

```bash
croc send --pass mySecretPassword document.pdf

```

Croc will output a receiver command that includes the authentication flag:

```bash
Code is: 1234-5678-9012

On the other computer run:
    croc --pass mySecretPassword 1234-5678-9012

```

### Receiving with Password Authentication

The receiver must execute the complete command including the password to authenticate successfully:

```bash
croc --pass mySecretPassword 1234-5678-9012

```

Omitting the flag or providing an incorrect password results in an immediate connection failure with a "could not secure channel" error.

### Using Environment Variables

For automation scripts where command-line arguments might expose sensitive data in shell history, use the environment variable:

```bash
export CROC_PASS=mySecretPassword
croc send document.pdf

```

The **determinePass** function in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go) automatically reads this variable when the `--pass` flag is absent.

### Programmatic Implementation in Go

When embedding Croc's client library directly in Go applications, set the password in the **Options** struct:

```go
import "github.com/schollz/croc/v9/src/croc"

opts := croc.Options{
    RelayAddress:  "relay://custom.example.com:9009",
    RelayPassword: "mySecretPassword",
    RoomName:      "secure-room",
}

client, err := croc.NewClient(opts)
if err != nil {
    log.Fatal(err)
}

```

This approach bypasses the CLI parsing layer and injects the password directly into the connection logic.

## Summary

Croc's password relay authentication mechanism operates through three distinct phases:

- **CLI Parsing**: The **determinePass** function in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go) extracts passwords from the `--pass` flag or `CROC_PASS` environment variable.
- **Command Construction**: In [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), custom passwords are appended to the receiver's command string via **flags.WriteString** when they differ from **models.DEFAULT_PASSPHRASE**.
- **Network Authentication**: The **tcp.ConnectToTCPServer** function in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) transmits the password during the initial TCP handshake, validating the client before data transfer begins.

## Frequently Asked Questions

### How does Croc handle the --pass flag internally?

Croc processes the flag through the **determinePass** helper in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go), which assigns the value to **Options.RelayPassword**. This value is then passed to **tcp.ConnectToTCPServer** during the relay connection phase to authenticate the client session against the relay's access control list.

### Can I set a custom password via environment variables?

Yes. The **determinePass** function checks for the `CROC_PASS` environment variable as a fallback when the `--pass` flag is not explicitly provided. This allows secure configuration in CI/CD pipelines without exposing credentials in command history or process listings.

### What happens if the relay password is incorrect?

If the password provided via `--pass` or `CROC_PASS` does not match the relay's expected credential, **tcp.ConnectToTCPServer** returns an authentication error immediately after the TCP handshake. The client displays a "could not secure channel" message and terminates the connection attempt before any file data is exchanged.

### Is the password visible in process listings when using --pass?

Yes, when passed as a command-line flag, the password may appear in process listings (`ps` output) and shell history. For sensitive transfers, use the `CROC_PASS` environment variable instead, which keeps the credential out of the process argument list while still being processed by the **determinePass** function in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go).