Secondary user verification lets you add second-factor security to voice
commands. This lets you add additional security for certain actions such as
turning off a security camera or opening a door. Secondary user verification is
not tied to a specific device trait which allows you to decide when to have
Google Assistant issue a challenge. For example, you can choose
to issue a challenge for the [OnOff](https://developers.home.google.com/cloud-to-cloud/traits/onoff) trait for a
security camera, but not issue a challenge for the
[OnOff](https://developers.home.google.com/cloud-to-cloud/traits/onoff)
trait for a light. You can also have Assistant
issue challenges in certain situations for the same action. For example, you
can request that Assistant issue a challenge request to
open a door if an NFC keyfob is not in the proximity of that door, but not
issue a challenge if the keyfob is present.

The Assistant can issue two types of challenges -
explicit acknowledgement or personal identification number (PIN). This adds a
challenge block to `QUERY` and `EXECUTE` intents sent from Assistant back to your action and accepts a `challengeNeeded` error
response. Assistant then sends back the intent request to
your action with the challenge data in the challenge block. You can then
validate the challenge data to determine if the user gave the correct security
response.

> [!CAUTION]
> **Caution:** Secondary user verification with PIN must be implemented for all the device types and traits that if unintentionally used can put the home in a substantial risk state.

Assistant uses dialog to issue the challenge, but if you
use Assistant on non-voice surfaces, PIN and
confirmations are done on-screen.

> [!NOTE]
> **Note:** Secondary user verification does not work with Google Workspace accounts.

## When to use secondary user verification

You can enable secondary user verification for any device type or trait.
However, you must implement secondary user verification for certain
security-sensitive device types and traits to get your integration certified.

Secondary user verification using the `pinNeeded` challenge type is required
for the following trait and device type combinations:

- The `OnOff` trait if the device type is `CAMERA`.
- The `OpenClose` trait if the device type is `DOOR`, `GARAGE`, `GATE`, or `WINDOW`.
- The `LockUnlock` trait when unlocking.
- The `ArmDisarm` trait when disarming or cancelling a disarm.
- The `Reboot`, `SoftwareUpdate`, or `NetworkControl` trait if the device type is `NETWORK` or `ROUTER`.

The `ackNeeded` challenge type is required for the `TemperatureSetting` trait
if the device type is `AC_UNIT` and the integration is location in Japan.

## Supported challenge types

These are the supported secondary user verification challenge types:

- [No challenge](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#no-challenge) - A request and response that does not use a Secondary user verification challenge.
- [ackNeeded](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#ackneeded) - A secondary user verification that requires explicit acknowledgement (yes or no) and can also use trait states as response feedback. This challenge type is not recommended for security devices and traits.
- [pinNeeded](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#pinneeded) - A secondary user verification that requires a personal identification number (PIN), which is ideal for security devices and traits.

> [!CAUTION]
> **Caution** : If you decide to allow users to opt-out of secondary user verification, you must provide a warning message to them to indicate the potential change to an unsecure state. For example:
>
> ***By
> opting out you are agreeing that your devices can be controlled without
> secondary user verification, potentially leading to an unsecure state (or less
> secure setting)***

### No challenge

This example shows a successful `EXECUTE` request and response without a
challenge for turning on the lights.

|---|---|
| **User** | Turn on the lights. |
| **Google Assistant** | Ok, turning on 3 lights. |

Request

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.OnOff",
          "params": {
            "on": true
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "on": true,
        "online": true
      }
    }]
  }
}
```

### ackNeeded

A secondary user acknowledgement authentication that can use multiple states
for a trait or a simple acknowledgement authentication.

> [!NOTE]
> **Note:** The `ackNeeded` challenge type is not recommended for security devices and traits.

There are the following types of `ackNeeded` challenge types:

- [ackNeeded simple](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#ackneeded-simple)
- [ackNeeded with trait states](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#ackneeded-trait-states)

#### ackNeeded simple

This example shows a simple request and response with a `ackNeeded` challenge
to dim a light and the confirmation to dim the light.

|---|---|
| **User** | Dim the living room light. |
| **Google Assistant** | Dimming the living room light. Are you sure? |
| **User** | Yes. |
| **Google Assistant** | Dimming the living room light. |

Request 1

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.BrightnessAbsolute",
          "params": {
            "brightness": 12
          }
        }]
      }]
    }
  }]
}
```
Response 1

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "ERROR",
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "ackNeeded"
      }
    }]
  }
}
```
Request 2

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.BrightnessAbsolute",
          "params": {
            "brightness": 12
          },
          "challenge": {
            "ack": true
          }
        }]
      }]
    }
  }]
}
```
Response 2

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS"
    }]
  }
}
```

#### ackNeeded with trait states

A secondary user acknowledgement authentication that can use states for a
trait.
For example, if you are working with the
[TemperatureSetting](https://developers.home.google.com/cloud-to-cloud/traits/temperaturesetting) trait and both
`thermostatMode` and `thermostatTemperatureSetpoint` are set,
Assistant can ask *Are you sure you want to set the heat
on the air conditioner to 28 degrees?*

You can also include a state in a response to have
Assistant perform a specific action based on a given
request.

The following traits and states support `ackNeeded` with trait states. A
listing of a specific trait indicates that all of its states are supported.

- [ArmDisarm](https://developers.home.google.com/cloud-to-cloud/traits/armdisarm)
  - Use the `ackNeeded` challenge type to arm or cancel arming the device, but for disarm and cancel disarm functions, the `pinNeeded` challenge type is required.
- [Fill](https://developers.home.google.com/cloud-to-cloud/traits/fill)
- [LockUnlock](https://developers.home.google.com/cloud-to-cloud/traits/lockunlock)
  - Use the `ackNeeded` challenge type to lock the device and the `pinNeeded` challenge type for unlocking.
- [OnOff](https://developers.home.google.com/cloud-to-cloud/traits/onoff)
  - `on`
  - Use the `ackNeeded` challenge type for this trait. The `pinNeeded` challenge type is required when this trait is used with `CAMERA` devices.
- [OpenClose](https://developers.home.google.com/cloud-to-cloud/traits/openclose)
  - Use the `ackNeeded` challenge type for this trait. The `pinNeeded` challenge type is required when this trait is used with `DOOR`, `GARAGE`, `GATE` or `WINDOW` devices.
- [Scene](https://developers.home.google.com/cloud-to-cloud/traits/scene)
- [TemperatureSetting](https://developers.home.google.com/cloud-to-cloud/traits/temperaturesetting)
  - `thermostatMode`
  - `thermostatTemperatureSetpoint`
  - `thermostatTemperatureSetpointHigh`
  - `thermostatTemperatureSetpointLow`

This example shows a request and response with an `ackNeeded` challenge that
uses a trait state. It changes the air conditioner mode to heat and sets the
temperature to 28 degrees. Then, Assistant asks the users
for the acknowledgement to turn on the heat and set the temperature to 28
degrees since a `thermostatTemperatureSetpoint` of `28` is returned as a state
in the response.

|---|---|
| **User** | Set AC mode to heat. |
| **Google Assistant** | Are you sure you want to set the heat on the air conditioner to 28 degrees? |
| **User** | Yes. |
| **Google Assistant** | Setting the heat on the air conditioner to 28 degrees. |

Request 1

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.TemperatureSetting",
          "params": {
            "thermostatMode": "heat"
          }
        }]
      }]
    }
  }]
}
```
Response 1

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "ERROR",
      "states": {
        "thermostatMode": "heat",
        "thermostatTemperatureSetpoint": 28
      },
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "ackNeeded"
      }
    }]
  }
}
```
Request 2

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.TemperatureSetting",
          "params": {
            "thermostatMode": "heat"
          },
          "challenge": {
            "ack": true
          }
        }]
      }]
    }
  }]
}
```
Response 2

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "thermostatMode": "heat",
        "thermostatTemperatureSetpoint": 28
      }
    }]
  }
}
```

### pinNeeded

The `pinNeeded` challenge is recommended for security devices.

This example shows an initial request and response with a `pinNeeded`
challenge. The example returns a response with a `pinNeeded` challenge, so
Assistant asks for the pin. At this point, the user can
provide an incorrect or valid pin.

Sample request and response for an incorrect or valid PIN:

- [Incorrect PIN](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#incorrect-pin)
- [Valid PIN](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#valid-pin)

> [!NOTE]
> **Note:** Users must be able to set their own PIN.

|---|---|
| **User** | Unlock the door. |
| **Google Assistant** | Can I have your security code? |

Request

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.LockUnlock",
          "params": {
            "lock": false
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "ERROR",
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "pinNeeded"
      }
    }]
  }
}
```

#### Incorrect PIN

This example shows the request and response with a `challengeFailedPinNeeded`
challenge. This challenge should be used after an initial `pinNeeded` challenge
failed.

When a `challengeFailedPinNeeded` type is returned,
Assistant asks for the security code again. If the user
performs too many failed attempts, you can return a `tooManyFailedAttempts`
error response. See [Error responses](https://developers.home.google.com/cloud-to-cloud/enhancements/secondary-user-verification#error-responses).

|---|---|
| **User** | 333222 |
| **Google Assistant** | Sorry, the security code is incorrect. Can I have your security code? |

Request

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.LockUnlock",
          "params": {
            "lock": false
          },
          "challenge": {
            "pin": "333222"
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "ERROR",
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "challengeFailedPinNeeded"
      }
    }]
  }
}
```

#### Valid PIN

This example shows the request and response of a valid PIN.

|---|---|
| **User** | 333444 |
| **Google Assistant** | Unlocking the door. |

Request

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.LockUnlock",
          "params": {
            "lock": false
          },
          "challenge": {
            "pin": "333444"
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "isLocked": false,
        "isJammed": false
      }
    }]
  }
}
```

|---|---|
| **User** | Dim the living room light. |
| **Google Assistant** | Can I have your security code? |

Request

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "inputs": [{
    "intent": "action.devices.EXECUTE",
    "payload": {
      "commands": [{
        "devices": [{
          "id": "123"
        }],
        "execution": [{
          "command": "action.devices.commands.BrightnessAbsolute",
          "params": {
            "brightness": 12
          }
        }]
      }]
    }
  }]
}
```
Response

```
{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "ERROR",
      "errorCode": "challengeNeeded",
      "challengeNeeded": {
        "type": "pinNeeded"
      }
    }]
  }
}
```

## Error responses

These are some error codes that can be returned with your responses:

- **tooManyFailedAttempts** - *Sorry, too many failed attempts. Please go to your device's app to complete that action.*
- **pinIncorrect** - *Sorry, the security code is incorrect.*
- **userCancelled** - *Ok*

See the full list of
[errors and exceptions](https://developers.home.google.com/cloud-to-cloud/intents/errors-exceptions).