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

# Shared Secret Authentication

> Use a product key and secret for simple HMAC-based device authentication. The fastest way to connect devices — ideal for development and prototyping.

Shared Secret authentication is the simplest way to connect a Nerves device to NervesHub. Instead of provisioning individual X.509 certificates, every device in a product shares a `product_key` and `product_secret` pair. The device derives an HMAC credential from these values at runtime and presents it to NervesHub when opening its WebSocket connection. No client certificates or hardware security modules are required, making this mode fast to set up and easy to iterate on during development.

<Warning>
  Shared Secret authentication is designed for **development and prototyping**. Because all devices in a product share the same credentials, a compromised device exposes the secret for the entire fleet. For production deployments, migrate to [Device Certificates](./device-certificates) or [NervesKey](./nerveskey) so each device carries a unique, independently revocable identity.
</Warning>

## How It Works

When a device running `nerves_hub_link` starts, it reads the configured `product_key` and `product_secret`, computes an HMAC-based authentication token, and presents that token during the Phoenix Channel handshake over the secure WebSocket connection. NervesHub verifies the token against the product's registered secret and, if valid, accepts the connection. Because the credential is derived rather than static, the raw secret is never transmitted over the wire.

The device identifier used in this mode is the device's hardware serial number or a value you supply — there is no per-device certificate to manage or rotate.

## Find Your Credentials

Retrieve your product credentials from the NervesCloud UI:

<Steps>
  <Step title="Open Product Settings">
    In [NervesCloud](https://manage.nervescloud.com), navigate to your organization and select the product you want to connect devices to.
  </Step>

  <Step title="Open the Shared Secret Tab">
    Click **Settings** in the left sidebar, then select the **Shared Secret** tab.
  </Step>

  <Step title="Copy Your Credentials">
    Copy the **Product Key** and **Product Secret** values. Treat the product secret like a password — do not commit it to source control.
  </Step>
</Steps>

## Configure NervesHubLink

Add `nerves_hub_link` to your Nerves project if you have not already, then configure the shared secret in `config/target.exs`:

```elixir theme={null}
# mix.exs
def deps do
  [
    {:nerves_hub_link, "~> 2.7"}
  ]
end
```

```elixir theme={null}
# config/target.exs
config :nerves_hub_link,
  host: "devices.nervescloud.com",
  remote_iex: true,
  shared_secret: [
    product_key: System.get_env("NERVES_HUB_PRODUCT_KEY"),
    product_secret: System.get_env("NERVES_HUB_PRODUCT_SECRET")
  ]
```

Set the environment variables in your build environment before running `mix firmware`:

```bash theme={null}
export NERVES_HUB_PRODUCT_KEY="your-product-key"
export NERVES_HUB_PRODUCT_SECRET="your-product-secret"
```

<Tip>
  Using `System.get_env/1` in `config/target.exs` bakes the values into the firmware at compile time. If you need to supply or rotate credentials at runtime — for example, reading them from a provisioned file on the device — use the `NervesHubLink.Configurator` behaviour instead (see below).
</Tip>

## Securing Credentials

### Use Environment Variables

Never hardcode `product_key` or `product_secret` directly in source files. Pass them through environment variables in your CI/CD pipeline or local build environment as shown above. This keeps secrets out of version control and lets you rotate them without changing code.

### Runtime Configuration with Configurator

For more flexible credential management, implement the `NervesHubLink.Configurator` behaviour. This callback runs on device boot and lets you read credentials from any source — a provisioned file, an encrypted store, or a remote endpoint:

```elixir theme={null}
defmodule MyApp.NervesHubConfigurator do
  @behaviour NervesHubLink.Configurator

  @impl true
  def build_config(config) do
    product_key    = File.read!("/data/provisioning/product_key") |> String.trim()
    product_secret = File.read!("/data/provisioning/product_secret") |> String.trim()

    %{
      config
      | shared_secret: [
          product_key: product_key,
          product_secret: product_secret
        ]
    }
  end
end
```

Then point `nerves_hub_link` at your configurator module:

```elixir theme={null}
# config/target.exs
config :nerves_hub_link,
  host: "devices.nervescloud.com",
  configurator: MyApp.NervesHubConfigurator
```

### Rotating the Product Secret

If your product secret is compromised, rotate it immediately in **Product Settings → Shared Secret** in the NervesCloud UI. Devices using the old secret will be disconnected until they receive the new value. Plan a rotation strategy before you go to production — this is another reason to prefer Device Certificates for production fleets.

## Next Steps

Once you are ready to move beyond development, migrate your devices to a stronger authentication method:

<CardGroup cols={2}>
  <Card title="Device Certificates" icon="certificate" href="./device-certificates">
    Provision each device with a unique X.509 certificate signed by your own CA. The recommended approach for production fleets.
  </Card>

  <Card title="NervesKey" icon="microchip" href="./nerveskey">
    Store device private keys in a hardware security module — keys never leave the chip.
  </Card>
</CardGroup>
