Class: SpreeCmCommissioner::Telegram::ExchangeOauthToken

Inherits:
Object
  • Object
show all
Includes:
Spree::ServiceModule::Base
Defined in:
app/services/spree_cm_commissioner/telegram/exchange_oauth_token.rb

Overview

Exchanges a Telegram OAuth authorization code for an id_token at Telegram's token endpoint. This is the server-side half of the mobile/web PKCE login: the client cannot call Telegram's /token directly (native apps have no registered HTTPS origin, and browsers are blocked by CORS), so it relays the exchange through us.

Telegram validates the redirect_uri parameter against a BotFather- registered domain, not the caller's host, so this can safely run from the API server. This Telegram Login Widget client is confidential (it has a client_secret), so PKCE alone isn't enough — Telegram's /token endpoint still requires client_secret, which is why it must be injected here server-side rather than sent by the app.

client_secret is resolved by the caller (which has tenant context from the request) and passed in like any other param - this service only forwards it to Telegram, it never looks up a tenant/store itself.

Docs: https://core.telegram.org/bots/telegram-login

Constant Summary collapse

TOKEN_ENDPOINT =
'https://oauth.telegram.org/token'.freeze
REQUIRED_PARAMS =
%i[client_id code redirect_uri code_verifier].freeze

Instance Method Summary collapse

Instance Method Details

#call(client_id:, code:, redirect_uri:, code_verifier:, client_secret:) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/services/spree_cm_commissioner/telegram/exchange_oauth_token.rb', line 28

def call(client_id:, code:, redirect_uri:, code_verifier:, client_secret:)
  missing = missing_param(client_id: client_id, code: code, redirect_uri: redirect_uri, code_verifier: code_verifier)
  return failure(nil, "#{missing}_missing") if missing
  return failure(nil, 'telegram_oauth_client_secret_not_configured') if client_secret.blank?

  begin
    response = post_to_telegram(
      client_id: client_id, code: code, redirect_uri: redirect_uri,
      code_verifier: code_verifier, client_secret: client_secret
    )
  rescue StandardError => e
    CmAppLogger.error(label: 'telegram_token_exchange_failed', data: e.message)
    return failure(nil, 'telegram_token_exchange_failed')
  end

  success(status: response.code.to_i, body: response.body)
end