> ## Documentation Index
> Fetch the complete documentation index at: https://omniflow-vpn.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 0007 — Customers do not sign in with a password

> Why the customer panel offers Telegram, OIDC, and a bot-delivered link but no password, what that costs an installation, and the condition under which it would be added

**Status:** Accepted.

## Context

A customer reaches their account three ways: the Telegram login widget in a
browser, the Mini App's signed `initData` inside Telegram, and a generic OIDC
provider an operator has configured. A fourth, the sign-in link, is a fallback
requested from the bot rather than from a web form.

A password is absent. Operators have one — `internal/adminauth` hashes it,
rate-limits it, locks the account out, pairs it with TOTP or a passkey, and
notifies on every credential change — so the absence on the customer side is not
a gap in what the codebase can do. It was a choice, and until this record it was
written down nowhere, which made it read as an oversight to anybody who compared
the two route lists.

Three facts about this installation shape the choice.

**There is no e-mail transport.** No SMTP client, no provider adapter, no
configuration for either. The operator password-reset flow issues a token only
from a command run on the server, which prints it for out-of-band delivery —
defensible for a handful of operators who can reach each other, and not a
customer-facing mechanism.

**Answering "do you know this address?" is the thing the panel refuses to do.**
It is why the sign-in link starts in a chat the customer has already
authenticated to, and why a contact address already registered elsewhere is
refused as "not available here" and nothing more. A password form has to take an
identifier and then either accept it or reject it, and every version of that
answer tells a stranger whether somebody is a customer here.

**A customer already arrives holding a stronger credential.** Telegram and an
OIDC provider both authenticate the person before Omniflow sees them, and both
can carry a second factor that Omniflow does not have to implement, store, or
recover.

## Decision

**The customer panel does not offer a password, and `customer_identities` never
stores a secret.** A customer authenticates through a party that already
authenticated them — Telegram or an OIDC provider — or through a link the bot
delivers into a chat they already control.

**The absence is a property of the schema, not of the UI.** There is no
password column, no reset-token table, and no hashing parameters on the customer
side. A future screen cannot quietly reintroduce one; adding it means a
migration and superseding this record.

**Adding a customer password requires an e-mail channel first.** A password
without a reset path locks people out permanently, and a reset path needs a
delivery channel that reaches a customer who by definition cannot sign in.
Telegram is not that channel: the customers who would most want a password are
the ones who do not have Telegram.

## Consequences

**An installation must enable at least one of Telegram or OIDC, or nobody can
sign in on the web.** This is the real cost and it is not small. An operator
selling into a market where Telegram is blocked and no consumer identity
provider is acceptable has no configuration that works, and no amount of
configuration produces one. `GET /v1/account/auth/methods` returns an empty list
and the sign-in screen says so plainly rather than rendering a form that cannot
succeed.

**A customer database leak carries no credential to crack.** There is nothing to
hash badly, nothing to reuse across sites, and nothing an offline attack can
work on. This is the security property the decision buys, and it is worth more
than the convenience it costs.

**Whole categories of work do not exist.** No breach-list check, no password
strength meter on the customer side, no lockout tuning, no reset-token expiry
policy, no credential-change notification path, no "your password was changed"
support script. Password reset is the largest single support category in
consumer products, and this installation has none of it.

**The account recovery story is somebody else's.** A customer who loses access
to their Telegram account or their identity provider recovers it there, not
here. The panel's handoff for identity conflicts and irreversible actions points
at support, and support's answer is to help them prove control of the upstream
account rather than to issue a new credential.

## Revisit when

* **E-mail transport exists and is a supported, configured channel** rather than
  a documented absence. Until then a password is a credential with no recovery
  path, which is worse than no password.
* **A concrete installation demonstrates customers it cannot sign in** — not a
  preference for passwords, but a market where neither Telegram nor any
  acceptable OIDC provider is available. That is the observable condition, and
  it is the one that would justify paying for the whole stack above.

Note that a verified e-mail address is already stored as a contact channel and
is already used for consent and delivery preferences. Its existence is not the
condition; a transport that can send to it is.

## Related

* [Customer web panel](https://omniflow-vpn.mintlify.site/customer/web-panel.md#sign-in) — the three methods, and what each refuses.
* [OIDC providers](https://omniflow-vpn.mintlify.site/integrations/oidc.md) — configuring an identity provider for customers and for operators.
* [Security](https://omniflow-vpn.mintlify.site/operations/security.md) — the operator credential stack this record deliberately does not mirror.
* [Privacy](https://omniflow-vpn.mintlify.site/operations/privacy.md) — what an installation stores about a customer, and what it does not.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.