Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting access token without browser #10784

Open
lofti198 opened this issue Jan 30, 2025 · 1 comment
Open

Getting access token without browser #10784

lofti198 opened this issue Jan 30, 2025 · 1 comment
Assignees

Comments

@lofti198
Copy link

My code below is triggering browser page to be opened to get access token, despite I choose option to avoid browser opening when registered application. Please suggest me what am I doing wrong or maybe I am using another scheme of interaction?

using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using Allegro.Shared.Models;

namespace Allegro.Shared.Services
{
    public class AllegroApiServiceBase
    {

        protected readonly HttpClient _httpClient;
        protected readonly string _clientId;
        protected readonly string _clientSecret;
        public AllegroApiServiceBase(HttpClient httpClient, string clientId, string clientSecret)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
            _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
            _clientSecret = clientSecret ?? throw new ArgumentNullException(nameof(clientSecret));
        }

        public async Task<DeviceAuthResponse> GetDeviceCodeAsync()
        {
            var credentials = $"{_clientId}:{_clientSecret}";
            var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Credentials);

            var payload = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                { "client_id", _clientId },
                { "scope", "allegro:api:sale:offers:write allegro:api:sale:offers:read allegro:api:orders:read allegro:api:sale:settings:read" }
            });

            var response = await _httpClient.PostAsync("https://allegro.pl/auth/oauth/device", payload);

            if (!response.IsSuccessStatusCode)
            {
                throw new Exception($"Failed to get device code. Status code: {response.StatusCode}");
            }

            var responseContent = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<DeviceAuthResponse>(responseContent)
                ?? throw new Exception("Failed to parse device authorization response.");
        }

        public async Task<TokenResponse?> PollForAccessTokenAsync(string deviceCode, int intervalSeconds)
        {
            while (true)
            {
                await Task.Delay(intervalSeconds * 1000);

                var credentials = $"{_clientId}:{_clientSecret}";
                var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Credentials);

                var payload = new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "grant_type", "urn:ietf:params:oauth:grant-type:device_code" },
                    { "device_code", deviceCode }
                });

                var response = await _httpClient.PostAsync("https://allegro.pl/auth/oauth/token", payload);
                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    return JsonSerializer.Deserialize<TokenResponse>(responseContent);
                }

                var errorResponse = JsonSerializer.Deserialize<ErrorResponse>(responseContent);
                if (errorResponse?.Error == "authorization_pending")
                {
                    continue;
                }
                else if (errorResponse?.Error == "access_denied")
                {
                    throw new Exception("User denied access.");
                }
                else
                {
                    throw new Exception($"Unexpected error: {responseContent}");
                }
            }
        }

        public async Task<TokenResponse?> RefreshAccessTokenAsync(string refreshToken)
        {
            var credentials = $"{_clientId}:{_clientSecret}";
            var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));

            var payload = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                { "grant_type", "refresh_token" },
                { "refresh_token", refreshToken }
            });

            var request = new HttpRequestMessage(HttpMethod.Post, "https://allegro.pl/auth/oauth/token")
            {
                Content = payload
            };
            request.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64Credentials);

            var response = await _httpClient.SendAsync(request);

            if (!response.IsSuccessStatusCode)
            {
                return null;
            }

            var responseContent = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<TokenResponse>(responseContent);
        }

    }
}

@PrzemyslawLukanowski
Copy link
Collaborator

Hello, the device code authorization flow requires the user to log in to their account via a browser. This is necessary to complete the user_code verification at the verification_uri and associate the application with the account. This is the intended behavior.

If you are experiencing a different issue, can you send us more details?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants