# Credentials Login

**Usage:** `"template": "login_credentials"`

<figure><img src="/files/4qk7jXfIOHXxPGreWLI1" alt=""><figcaption></figcaption></figure>

{% code title="/drivers/\<driver\_id>/driver.compose.json" %}

```javascript
{
  "name": { "en": "My Driver" },
  "images": {
    "small": "/drivers/my_driver/assets/images/small.png",
    "large": "/drivers/my_driver/assets/images/large.png"
  },
  "pair": [
    {
      "id": "login_credentials",
      "template": "login_credentials",
      "options": {
        "logo": "logo.png",
        "title": {
          "en": "Your custom title"
        },
        "usernameLabel": { "en": "E-mail address" },
        "usernamePlaceholder": { "en": "john@doe.com" },
        "passwordLabel": { "en": "Password" },
        "passwordPlaceholder": { "en": "Password" }
      }
    },
    {
      "id": "list_devices",
      "template": "list_devices",
      "navigation": { "next": "add_devices" }
    },
    {
      "id": "add_devices",
      "template": "add_devices"
    }
  ]
}
```

{% endcode %}

## **Options**

| Key                   | Type                                                          | Default            | Description                   |
| --------------------- | ------------------------------------------------------------- | ------------------ | ----------------------------- |
| `title`               | [translation object](/the-basics/app/internationalization.md) |                    |                               |
| `logo`                | `string`                                                      | `null`             | A path to an image for a logo |
| `usernameLabel`       | [translation object](/the-basics/app/internationalization.md) | `"E-mail address"` |                               |
| `usernamePlaceholder` | [translation object](/the-basics/app/internationalization.md) | `"john@doe.com"`   |                               |
| `passwordLabel`       | [translation object](/the-basics/app/internationalization.md) | `"Password"`       |                               |
| `passwordPlaceholder` | [translation object](/the-basics/app/internationalization.md) | `"Password"`       |                               |

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/drivers/\<driver\_id>/driver.js" %}

```javascript
const Homey = require("homey");
const DeviceAPI = require("device-api");

class Driver extends Homey.Driver {
  async onPair(session) {
    let username = "";
    let password = "";

    session.setHandler("login", async (data) => {
      username = data.username;
      password = data.password;

      const credentialsAreValid = await DeviceAPI.testCredentials({
        username,
        password,
      });

      // return true to continue adding the device if the login succeeded
      // return false to indicate to the user the login attempt failed
      // thrown errors will also be shown to the user
      return credentialsAreValid;
    });

    session.setHandler("list_devices", async () => {
      const api = await DeviceAPI.login({ username, password });
      const myDevices = await api.getDevices();

      const devices = myDevices.map((myDevice) => {
        return {
          name: myDevice.name,
          data: {
            id: myDevice.id,
          },
          settings: {
            // Store username & password in settings
            // so the user can change them later
            username,
            password,
          },
        };
      });

      return devices;
    });
  }
}

module.exports = Driver;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/drivers/\<driver\_id>/driver.mts" %}

```mts
import Homey from "homey";
import DeviceApi from "./device-api.mjs";

type LoginData = {
  username: string;
  password: string;
};

export default class Driver extends Homey.Driver {
  async onPair(session: Homey.Driver.PairSession): Promise<void> {
    let username = "";
    let password = "";

    session.setHandler("login", async (data: LoginData): Promise<boolean> => {
      username = data.username;
      password = data.password;

      const credentialsAreValid = await DeviceApi.testCredentials(username, password);

      // return true to continue adding the device if the login succeeded
      // return false to indicate to the user the login attempt failed
      // thrown errors will also be shown to the user
      return credentialsAreValid;
    });

    session.setHandler("list_devices", async (): Promise<object[]> => {
      const api = await DeviceApi.login(username, password);
      const myDevices = await api.getDevices();

      const devices = myDevices.map(myDevice => {
        return {
          name: myDevice.name,
          data: {
            id: myDevice.id,
          },
          settings: {
            // Store username & password in settings
            // so the user can change them later
            username: username,
            password: password,
          },
        };
      });

      return devices;
    });
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/drivers/\<driver\_id>/driver.py" %}

```python
from typing import TypedDict

from device_api import DeviceApi
from homey import driver
from homey.driver import ListDeviceProperties
from homey.pair_session import PairSession


class LoginData(TypedDict):
    username: str
    password: str


class Driver(driver.Driver):
    async def on_pair(self, session: PairSession) -> None:
        username, password = "", ""

        async def on_login(data: LoginData) -> bool:
            nonlocal username, password
            username = data["username"]
            password = data["password"]

            credentials_are_valid = await DeviceApi.test_credentials(**data)

            # return true to continue adding the device if the login succeeded
            # return false to indicate to the user the login attempt failed
            # thrown errors will also be shown to the user
            return credentials_are_valid

        async def on_list_devices() -> list[ListDeviceProperties]:
            api = await DeviceApi.login(username, password)
            my_devices = await api.get_devices()

            devices: list[ListDeviceProperties] = [
                {
                    "name": device.name,
                    "data": {"id": device.id},
                    "settings": {
                        # Store username & password in settings
                        # so the user can change them later
                        "username": username,
                        "password": password,
                    },
                }
                for device in my_devices
            ]

            return devices


homey_export = Driver

```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://apps.developer.homey.app/the-basics/devices/pairing/system-views/credentials-login.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
