Mini App sign-in
Both Telegram Mini Apps, the professional app (apps/master_tg_app) and the
client app (apps/client_tg_app), sign in the same way. Neither shows a login
screen or asks for a phone, email, or password: opening the app from its bot is
enough.
One origin
Each Mini App talks only to the API, at VITE_API_URL:
| Routes | Used for |
|---|---|
/auth/*, served by channel authentication | Sign-in, session refresh, sign-out |
| Everything else | Business requests, with Authorization: Bearer <accessToken> |
Business routes never see Telegram launch data. VITE_CHANNEL_AUTH_APP names
the app the API knows this bot by. It defaults to professional or client
and must match a key in the API's CHANNEL_AUTH_TELEGRAM_APPS_JSON.
How a launch signs in
- The app asks the API for an exchange context for its app.
- It sends that context with Telegram's raw launch data.
- The API answers with a Supabase access token, refresh token, and expiry. From then on, the app calls the API with the access token.
The first authenticated request triggers this, so both steps happen as the app loads. The client app then checks contact separately; see Telegram client Mini App.
Keeping the session
- Memory only. The access and refresh tokens live in memory. They are never
written to
localStorage,sessionStorage, or cookies. - One renewal at a time. The app refreshes the session 60 seconds before the access token expires. Concurrent requests wait for the same refresh.
- Expired launch data is fine. Refresh uses the refresh token, so an app left open for hours keeps working after Telegram's launch data has expired.
- One retry. If the API rejects a token, the app renews the session and repeats that request once. A second rejection is reported, not retried.
- No automatic retries. If the API is unreachable, the request fails with a retryable message; the next request tries again.
- Reloads. The tab keeps its exchange context in
sessionStorage, so a reload within 10 minutes signs in again with the same launch data. Later, or in a new tab, the app needs fresh launch data.
When the session cannot be used
If the refresh session is gone and the launch data was already used, or the app was opened without launch data, the app shows a message to close it and open it again from Telegram. It offers no retry button, because only fresh launch data can sign in.
Signing out
Sign out (in the professional app's More screen and the client app's settings) revokes the refresh session through the API, forgets the tokens and the tab's exchange context, and shows the reopen message. The same launch data cannot sign in again; reopening the app from Telegram can. An access token issued before sign-out stays valid until it expires, because the API verifies tokens offline.
Local development
| App | Default API | Notes |
|---|---|---|
| Professional | Same origin as the page | The dev and preview servers proxy /auth and /professional to VITE_API_PROXY_TARGET (default http://127.0.0.1:3000), so one tunnel serves a phone |
| Client | http://127.0.0.1:3000 in development | Calls the API directly; in production its origin must be the API's CLIENT_APP_ORIGIN |
The API needs channel authentication configured; see Environment variables.
Browser previews
Opened outside Telegram, without launch data, both apps show labeled sample data and make no request to the API. Nothing from a preview creates a session or reaches the server.