Files
marketplaces/docs/TELEGRAM_USERAUTH_BACKEND.md
sdarbinyan 4d8dc6b59c api auth
2026-06-01 00:47:26 +04:00

7.7 KiB

Telegram UserAuth Backend Contract

This document extracts the existing Telegram login flow into a repo-neutral contract for reuse in other projects.

The UI behavior, payloads, polling cadence, and session model stay the same. Only route names and cookie naming are generalized.

Endpoint Renaming

Current app contract Reusable contract
GET /auth/session GET /userauth/session
POST /auth/qr/create POST /userauth/qr/create
GET /auth/qr/poll?token=... GET /userauth/qr/poll?token=...
POST /auth/qr/confirm POST /userauth/qr/confirm
GET /auth/telegram/callback GET /userauth/telegram/callback
POST /auth/logout POST /userauth/logout
POST /websession/{sessionId} POST /usersession/{sessionId}
Cookie dx_session Cookie userauth_session

Flow Summary

There are two supported flows.

1. Direct login from button

  1. Frontend opens https://t.me/{botUsername}?start=auth_{callbackUrl}.
  2. Telegram bot creates a session and sends the user a login button.
  3. The button points to GET /userauth/telegram/callback?token={sessionId}.
  4. Backend sets userauth_session cookie and redirects back to the storefront.
  5. Frontend calls GET /userauth/session and becomes authenticated.

2. QR login from desktop

  1. Frontend opens dialog.
  2. Frontend calls POST /userauth/qr/create.
  3. Backend returns { token, url } where url is a Telegram deep link.
  4. Frontend renders a QR from that URL.
  5. User scans QR and bot calls POST /userauth/qr/confirm.
  6. Frontend polls GET /userauth/qr/poll?token=... every 3 seconds.
  7. When status becomes confirmed, backend returns session payload and sets the cookie.
  8. Frontend syncs local cart using POST /usersession/{sessionId}.

Session Shape

The frontend expects this exact response shape for the authenticated session.

{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "telegramUserId": 123456789,
  "username": "ivan_petrov",
  "displayName": "Ivan Petrov",
  "active": true,
  "expiresAt": "2026-05-21T14:30:00Z"
}
Field Type Required Notes
sessionId string yes Session identifier used in cart sync
telegramUserId number yes Telegram user ID
username string or null no Telegram username
displayName string yes User-facing full name
active boolean yes false means expired session
expiresAt ISO 8601 string yes Used by frontend refresh scheduling

Recommended TTL:

  • Session TTL: 24 hours
  • QR token TTL: 5 minutes

HTTP Contract

POST /userauth/qr/create

Creates a one-time QR login token when the dialog opens.

Request body:

{}

Response 200:

{
  "token": "dG9rZW4tYWJjMTIz",
  "url": "https://t.me/userauth_bot?start=login_dG9rZW4tYWJjMTIz"
}

Requirements:

  • Generate a cryptographically secure token.
  • Save token with status pending.
  • Return a Telegram deep link in url.
  • Rate limit to 5 requests per minute per IP.

GET /userauth/qr/poll?token={token}

Called every 3 seconds until confirmation or expiration.

Possible responses:

Pending:

{ "status": "pending" }

Confirmed:

{
  "status": "confirmed",
  "session": {
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "telegramUserId": 123456789,
    "username": "ivan_petrov",
    "displayName": "Ivan Petrov",
    "active": true,
    "expiresAt": "2026-05-21T14:30:00Z"
  }
}

Expired:

{ "status": "expired" }

Behavior:

  • If confirmed, set cookie userauth_session in the response.
  • Delete or invalidate the QR token after the first successful confirmed poll.
  • If token is unknown or expired, return status: "expired".

POST /userauth/qr/confirm

Internal endpoint called by the Telegram bot after the user scans the QR code.

Required header:

X-Bot-Secret: <shared secret between bot and backend>

Request body:

{
  "token": "dG9rZW4tYWJjMTIz",
  "telegram_user": {
    "id": 123456789,
    "first_name": "Ivan",
    "last_name": "Petrov",
    "username": "ivan_petrov"
  }
}

Response 200:

{ "status": "ok" }

Behavior:

  • Validate X-Bot-Secret.
  • Validate token exists and is still pending.
  • Create a user session.
  • Store session ID on the QR token.
  • Mark QR token as confirmed.

GET /userauth/session

Returns the currently active session based on the cookie.

Frontend behavior depends on this endpoint in two places:

  • initial auth check on app startup
  • fallback polling if QR token creation fails

Response 200:

{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "telegramUserId": 123456789,
  "username": "ivan_petrov",
  "displayName": "Ivan Petrov",
  "active": true,
  "expiresAt": "2026-05-21T14:30:00Z"
}

Error handling:

  • Any non-200 response is treated by the frontend as unauthenticated.

GET /userauth/telegram/callback?token={sessionId}

Used for direct Telegram login from the primary button flow.

Behavior:

  • Read the token query param.
  • Resolve it to a valid active session.
  • Set cookie userauth_session.
  • Redirect user to the storefront URL.

POST /userauth/logout

Clears the backend session and expires the cookie.

Request body:

{}

Response 200:

{ "message": "ok" }

POST /usersession/{sessionId}

Synchronizes local cart immediately after successful login.

Request body:

[
  {
    "itemID": 123,
    "quantity": 2,
    "colour": "#ff0000",
    "size": "XL",
    "price": 1500
  }
]

Notes:

  • This payload is unchanged from the existing implementation.
  • price is already discounted on the frontend side.
  • The frontend skips the call if cart is empty.

Direct login link format:

https://t.me/{botUsername}?start=auth_{urlEncodedCallbackUrl}

QR login link format:

https://t.me/{botUsername}?start=login_{qrToken}

Important limit:

  • Telegram limits the start payload to 64 characters.
  • A base64url encoding of 32 random bytes plus login_ fits safely.

Use these cookie settings for the frontend to work correctly across site and API origins.

Property Value
Name userauth_session
Path /
HttpOnly true
Secure true
SameSite None
MaxAge 86400
Domain your shared parent domain, for example .example.com

CORS Requirements

Because the frontend sends credentials, backend must return an explicit origin.

Required headers:

Access-Control-Allow-Origin: https://your-frontend.example
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

Do not use * for Access-Control-Allow-Origin together with credentials.

Frontend Runtime Expectations

The current dialog behavior is fixed and should be preserved by backend responses.

  • QR polling interval: every 3 seconds
  • QR expiration on frontend: after 100 checks
  • If QR creation fails, frontend falls back to direct login URL and session polling
  • After login, frontend closes the dialog and re-checks session

Minimal Backend Checklist

  • Implement all six userauth endpoints and the usersession sync endpoint.
  • Store sessions for 24 hours.
  • Store QR tokens for 5 minutes.
  • Protect POST /userauth/qr/confirm with X-Bot-Secret.
  • Set userauth_session cookie on confirmed QR poll and direct callback.
  • Return the exact session JSON shape.
  • Support credentialed CORS.

Bot Checklist

  • Handle /start login_{token} and call POST /userauth/qr/confirm.
  • Handle /start auth_{callbackUrl} and provide a button that opens the callback URL.
  • Send success and expiration messages back to the user.
  • Share the same X-Bot-Secret value with backend.