Files
auth-service/TELEGRAM_USERAUTH_BACKEND.md
sdarbinyan 67b09147ea ppackage
2026-05-21 15:27:22 +04:00

8.9 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.

Package note:

  • The published telegram-userauth package does not require this direct flow by default.
  • If the host app provides telegram-login-url, the package button can use this flow.
  • If telegram-login-url is omitted, the package button opens the url returned by POST /userauth/qr/create.

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 5 seconds by default.
  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 5 seconds by default until confirmation or expiration.

Package note:

  • The reusable package exposes poll-interval-ms and defaults it to 5000.
  • Backend should not assume a stricter cadence than 5 seconds.

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

This endpoint is also used by the package after successful direct-login redirects and during fallback retries.

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 reusable package behavior should be preserved by backend responses.

  • QR polling interval: every 5 seconds by default
  • QR expiration on frontend: after 100 checks
  • If QR creation fails, frontend falls back to session polling
  • Primary button opens telegram-login-url when the host app provides one
  • Otherwise, primary button opens the deep link returned by POST /userauth/qr/create
  • After login, frontend emits an authenticated event to the host app

Package Integration Notes

The published package is a custom element named telegram-userauth.

Expected host configuration:

  • api-base-url for separate backend origins, or empty for same-origin deployments
  • optional telegram-login-url for dedicated direct-button flows
  • optional poll-interval-ms, default 5000

Expected package events:

  • userauth-authenticated with { session }
  • userauth-statechange with { state }
  • userauth-error with { message }

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.