# Sign-in prompt

> Asks to sign in, then shows the browser step, a code and Cancel. A Pyzed component for Python desktop GUIs, with examples and its API.

Source: https://albakore.github.io/pyzed/library/auth-prompt/

:::tip[In plain words]
A box that asks you to sign in, with a button for each way to do it.
:::

`ui.AuthPrompt` is a component that asks to sign in, for an agent or a service that needs it. It shows a `title`, an optional `detail` and one button per way to sign in: `methods` are dicts with `id`, `name` and optional `description` (shown as a tooltip) and `icon`, and the first one is the main button. Picking one reports `on_pick` with its id. While `waiting` holds that id it shows a spinner and what is happening (`waiting_text`, or "Waiting for the browser…"), the `code` to type with a copy button when there is one, Open the page again when `url` is set, and Cancel. `error` shows a message in red.

`ui.AuthPrompt` · Category: [AI agents](https://albakore.github.io/pyzed/library/#ai-agents) · [Full reference →](https://albakore.github.io/pyzed/reference/ui/#authprompt)

**Code:**

```python
pz.container(ui.AuthPrompt(
    title="Sign in to use the agent",
    detail="Your account is used to run the model.",
    methods=[{"id": "browser", "name": "Log in with the browser", "icon": "globe"},
             {"id": "key", "name": "Use an API key", "icon": "key-round"}],
    on_pick=on_pick,
), width=440)
```

:::note[New]
This component was added recently. Tell us how it works for you in the [issue tracker](https://github.com/albakore/pyzed/issues).
:::

## When to use

- Where an agent or a connected service needs the user to sign in before it can work.
- For a device sign-in: show the `code` the user types on the page that opened.

## Usage

```python
import pyzed as pz
from pyzed import ui

class Agent(pz.App):
    def __init__(self):
        self.waiting, self.code = "", ""

    def sign_in(self, method):
        self.waiting = method
        self.code = start_device_login()  # opens the browser and returns the code to type

    def view(self):
        return ui.AuthPrompt(title="Sign in to use the agent", waiting=self.waiting, code=self.code,
                             methods=[{"id": "browser", "name": "Log in with the browser"}],
                             on_pick=lambda e: self.sign_in(e.value),
                             on_cancel=lambda e: setattr(self, "waiting", ""),
                             on_copy=lambda e: pz.Command.copy(e.value))
```

## Variants

:::note[About these captures]
Each capture is recorded by pyzed itself, off-screen at 2x, in One Dark or One Light to match this site's theme, and cropped to the component so it shows at its real size. The pointer hovers, presses or types into it; a component that does not react to the pointer cycles through a few themes. With reduced motion you see the first frame. Open **Code** under a capture to see the snippet that draws it; free names such as `on_save` stand for your own callbacks.
:::

### Ways to sign in

The first method is the main (solid) button.

```python
pz.container(ui.AuthPrompt(title="Sign in to continue",
                           methods=[{"id": "browser", "name": "Log in with the browser"}]),
             width=380)
```

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", methods=[
    {"id": "browser", "name": "Log in with the browser", "icon": "globe"},
    {"id": "key", "name": "Use an API key", "icon": "key-round"},
]), width=380)
```

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", detail="The agent needs your account.",
                           methods=[{"id": "browser", "name": "Log in with the browser"}]),
             width=380)
```

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", error="The sign-in was cancelled.",
                           methods=[{"id": "browser", "name": "Try again"}]),
             width=380)
```

### Waiting

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="browser"), width=380)
```

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="cli",
                           waiting_text="Finish signing in in the terminal."),
             width=380)
```

```python
pz.container(ui.AuthPrompt(title="Sign in to continue", waiting="device", code="WDJB-MJHT",
                           url="https://example.com/device"), width=380)
```

## Events

Sign-in prompt has **4 events of its own**, listed below. Like every widget it also has the **18 common events** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), attached with `.on(...)`: see [Events](https://albakore.github.io/pyzed/guides/events/) and [Events of every component](https://albakore.github.io/pyzed/library/events/).

It is a `pz.Component`, so it also raises `on_mount` and `on_unmount`, and its handlers get a `pz.Event` whose `value` holds the data.

| Event | Handler gets | When |
| --- | --- | --- |
| `on_pick` | `(event)` | A method was picked (`event.value` is its id). |
| `on_cancel` | `(event)` | Cancel. |
| `on_open_url` | `(event)` | Open the page again. |
| `on_copy` | `(event)` | The code was copied. |

**Handler gets** is what Pyzed passes to your callable: `()` means nothing. Any handler can also be a message (a value that is not callable), which goes to `update()`.

### Handling the events

The same events written three ways. **Imperative**: methods of the app change `self`. **Declarative**: the handlers produce messages and one `update()` decides. **Functional**: a pure function draws an immutable state and asks for changes with `set_state(...)`. See [Imperative, declarative and functional](https://albakore.github.io/pyzed/guides/code-styles/).

**Imperative:**

```python
class Agent(pz.App):
    def __init__(self):
        self.waiting, self.code = "", ""

    def sign_in(self, method):           # on_pick: event.value is the method's id
        self.waiting, self.code = method, "ABCD-1234"

    def view(self):
        return ui.AuthPrompt(title="Sign in to use the agent", waiting=self.waiting, code=self.code,
                             methods=[{"id": "browser", "name": "Log in with the browser"}],
                             on_pick=lambda e: self.sign_in(e.value),
                             on_cancel=lambda e: setattr(self, "waiting", ""),
                             on_copy=lambda e: pz.Command.copy(e.value))   # the code
```

**Declarative:**

```python
from dataclasses import dataclass

@dataclass
class Picked:
    method: str

class Agent(pz.App):
    waiting = ""

    def update(self, message):
        match message:
            case Picked(method):
                self.waiting = method
            case "cancel":
                self.waiting = ""

    def view(self):
        return ui.AuthPrompt(title="Sign in", waiting=self.waiting,
                             methods=[{"id": "key", "name": "Use an API key"}],
                             on_pick=lambda e: Picked(e.value), on_cancel="cancel")
```

**Functional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    waiting: str = ""

def view(state, set_state):
    return ui.AuthPrompt(title="Sign in", waiting=state.waiting,
                         methods=[{"id": "browser", "name": "Log in with the browser"}],
                         on_pick=lambda e: set_state(waiting=e.value),
                         on_cancel=lambda e: set_state(waiting=""))
```

## Tips

:::tip
The copy button only reports `on_copy` with the code in `event.value`; return `pz.Command.copy(e.value)` from it to put the code on the clipboard.
:::

## Properties and API

### `ui.AuthPrompt`

```python
class AuthPrompt
```

A component that asks to sign in, like Zed when an agent needs it: one button per way to sign in, then, while one runs, what is happening (the browser or a terminal is open), a code to type when there is one, Open the page again and Cancel.

| Property | Default | Description |
| --- | --- | --- |
| `title` | `""` | The heading. |
| `detail` | `""` | A line under it. |
| `methods` | `None` | Dicts with `id`, `name`, optional `description` and `icon`; the first is the main one. |
| `waiting` | `""` | The id of the method in progress (`""` when none). |
| `waiting_text` | `""` | What to show while waiting. |
| `code` | `""` | A code to type (device sign-in). |
| `url` | `""` | The page that was opened. |
| `error` | `""` | An error to show. |
| `icon_name` | `"key-round"` | The icon. |
| `theme` | `None` | Theme. |

Events: `on_pick`, `on_cancel`, `on_open_url`, `on_copy` ([events](#events)).

[Full reference →](https://albakore.github.io/pyzed/reference/ui/#authprompt)

## Related

- [Callout](https://albakore.github.io/pyzed/library/callout/): An inline notice with a title, text and actions.
- [Button](https://albakore.github.io/pyzed/library/button/): The themed button: variants, sizes, icons and shortcuts.
- [Service row](https://albakore.github.io/pyzed/library/service-row/): A settings row for an MCP server, agent or skill: status, switch and menu.
