cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
Are you interested in learning how media industry leaders use Dropbox Replay? Register for our webinar here.

Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Exchanging code for token

Exchanging code for token

Shy1
Explorer | Level 3

I already have a topic, but I asked the wrong question and messed everything up. I think me need to create the right thread for the right question

 here is the code taken from the official dropbox source. I just tried to figure it out by pulling it into an empty project in parts, but when I gave up. turned to the original source, replacing the data with his own

if I take an example from github, and just change the AppKey and AppSecret and set my port, then following error: an error occurred while sending the request at the moment Exchanging code for token here

 

 

var tokenResult = await DropboxOAuth2Helper.ProcessCodeFlowAsync(redirectUri, ApiKey, ApiSecret, RedirectUri.ToString(), state);

 

 

all code from dropbox github

 

 

namespace OauthTest
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Runtime.InteropServices;
    using System.Threading.Tasks;

    using Dropbox.Api;

    partial class Program
    {
        // Add an ApiKey (from https://www.dropbox.com/developers/apps) here
        private const string ApiKey = "---";

        // Add an ApiSecret (from https://www.dropbox.com/developers/apps) here
        private const string ApiSecret = "---";

        // This loopback host is for demo purpose. If this port is not
        // available on your machine you need to update this URL with an unused port.
        private const string LoopbackHost = "http://127.0.0.1:4200/"; //deffault version 52475 my 4200

        // URL to receive OAuth 2 redirect from Dropbox server.
        // You also need to register this redirect URL on https://www.dropbox.com/developers/apps.
        private readonly Uri RedirectUri = new Uri(LoopbackHost + "authorize");

        // URL to receive access token from JS.
        private readonly Uri JSRedirectUri = new Uri(LoopbackHost + "token");


        [DllImport("kernel32.dll", ExactSpelling = true)]
        private static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [STAThread]
        static int Main(string[] args)
        {
            var instance = new Program();
            try
            {
                Console.WriteLine("Example OAuth Application");
                var task = Task.Run((Func<Task<int>>)instance.Run);

                task.Wait();

                return task.Result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw e;
            }
        }

        private async Task<int> Run()
        {
            DropboxCertHelper.InitializeCertPinning();

            string[] scopeList = new string[3] { "files.metadata.read", "files.content.read", "account_info.read" };
            var uid = await this.AcquireAccessToken(scopeList, IncludeGrantedScopes.None);
            if (string.IsNullOrEmpty(uid))
            {
                return 1;
            }

            // Specify socket level timeout which decides maximum waiting time when no bytes are
            // received by the socket.
            var httpClient = new HttpClient(new WebRequestHandler { ReadWriteTimeout = 10 * 1000 })
            {
                // Specify request level timeout which decides maximum time that can be spent on
                // download/upload files.
                Timeout = TimeSpan.FromMinutes(20)
            };

            try
            {
                var config = new DropboxClientConfig("SimpleOAuthApp")
                {
                    HttpClient = httpClient
                };

                var client = new DropboxClient(Settings.Default.AccessToken, Settings.Default.RefreshToken, ApiKey, ApiSecret, config);

                // This call should succeed since the correct scope has been acquired
                await GetCurrentAccount(client);
                
                Console.WriteLine("Refreshing without scope account_info.read");
                var newScopes = new string[] { "files.metadata.read", "files.content.read" };
                await client.RefreshAccessToken(newScopes);
                try
                {
                    // This should fail since token does not have "account_info.read" scope  
                    await GetCurrentAccount(client);
                }
                catch (Exception)
                {
                    Console.WriteLine("Correctly failed with invalid scope");
                }
                Console.WriteLine("Attempting to try again with include_granted_scopes");
                await this.AcquireAccessToken(newScopes, IncludeGrantedScopes.User);
                var clientNew = new DropboxClient(Settings.Default.AccessToken, Settings.Default.RefreshToken, ApiKey, ApiSecret, config);
                await GetCurrentAccount(clientNew);

                Console.WriteLine("Oauth Test Complete!");
                Console.WriteLine("Exit with any key");
                Console.ReadKey();
            }
            catch (HttpException e)
            {
                Console.WriteLine("Exception reported from RPC layer");
                Console.WriteLine("    Status code: {0}", e.StatusCode);
                Console.WriteLine("    Message    : {0}", e.Message);
                if (e.RequestUri != null)
                {
                    Console.WriteLine("    Request uri: {0}", e.RequestUri);
                }
            }

            return 0;
        }

        /// <summary>
        /// Handles the redirect from Dropbox server. Because we are using token flow, the local
        /// http server cannot directly receive the URL fragment. We need to return a HTML page with
        /// inline JS which can send URL fragment to local server as URL parameter.
        /// </summary>
        /// <param name="http">The http listener.</param>
        /// <returns>The <see cref="Task"/></returns>
        private async Task HandleOAuth2Redirect(HttpListener http)
        {
            var context = await http.GetContextAsync();

            // We only care about request to RedirectUri endpoint.
            while (context.Request.Url.AbsolutePath != RedirectUri.AbsolutePath)
            {
                context = await http.GetContextAsync();
            }

            context.Response.ContentType = "text/html";

            // Respond with a page which runs JS and sends URL fragment as query string
            // to TokenRedirectUri.
            using (var file = File.OpenRead("index.html"))
            {
                file.CopyTo(context.Response.OutputStream);
            }

            context.Response.OutputStream.Close();
        }

        /// <summary>
        /// Handle the redirect from JS and process raw redirect URI with fragment to
        /// complete the authorization flow.
        /// </summary>
        /// <param name="http">The http listener.</param>
        /// <returns>The <see cref="OAuth2Response"/></returns>
        private async Task<Uri> HandleJSRedirect(HttpListener http)
        {
            var context = await http.GetContextAsync();

            // We only care about request to TokenRedirectUri endpoint.
            while (context.Request.Url.AbsolutePath != JSRedirectUri.AbsolutePath)
            {
                context = await http.GetContextAsync();
            }

            var redirectUri = new Uri(context.Request.QueryString["url_with_fragment"]);
            
            return redirectUri;
        }

        /// <summary>
        /// Acquires a dropbox access token and saves it to the default settings for the app.
        /// <para>
        /// This fetches the access token from the applications settings, if it is not found there
        /// (or if the user chooses to reset the settings) then the UI in <see cref="LoginForm"/> is
        /// displayed to authorize the user.
        /// </para>
        /// </summary>
        /// <returns>A valid uid if a token was acquired or null.</returns>
        private async Task<string> AcquireAccessToken(string[] scopeList, IncludeGrantedScopes includeGrantedScopes)
        {
            Console.Write("Reset settings (Y/N) ");
            if (Console.ReadKey().Key == ConsoleKey.Y)
            {
                Settings.Default.Reset();
            }
            Console.WriteLine();

            var accessToken = Settings.Default.AccessToken;
            var refreshToken = Settings.Default.RefreshToken;

            if (string.IsNullOrEmpty(accessToken))
            {
                try
                {
                    Console.WriteLine("Waiting for credentials.");
                    var state = Guid.NewGuid().ToString("N");
                    var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Code, ApiKey, RedirectUri, state: state, tokenAccessType : TokenAccessType.Offline, scopeList : scopeList, includeGrantedScopes: includeGrantedScopes);
                    var http = new HttpListener();
                    http.Prefixes.Add(LoopbackHost);

                    http.Start();

                    System.Diagnostics.Process.Start(authorizeUri.ToString());

                    // Handle OAuth redirect and send URL fragment to local server using JS.
                    await HandleOAuth2Redirect(http);

                    // Handle redirect from JS and process OAuth response.
                    var redirectUri = await HandleJSRedirect(http);

                    Console.WriteLine("Exchanging code for token");
                    var tokenResult = await DropboxOAuth2Helper.ProcessCodeFlowAsync(redirectUri, ApiKey, ApiSecret, RedirectUri.ToString(), state);
                    Console.WriteLine("Finished Exchanging Code for Token");
                    // Bring console window to the front.
                    SetForegroundWindow(GetConsoleWindow());
                    accessToken = tokenResult.AccessToken;
                    refreshToken = tokenResult.RefreshToken;
                    var uid = tokenResult.Uid;
                    Console.WriteLine("Uid: {0}", uid);
                    Console.WriteLine("AccessToken: {0}", accessToken);
                    if (tokenResult.RefreshToken != null)
                    {
                        Console.WriteLine("RefreshToken: {0}", refreshToken);
                        Settings.Default.RefreshToken = refreshToken;
                    }
                    if (tokenResult.ExpiresAt != null)
                    {
                        Console.WriteLine("ExpiresAt: {0}", tokenResult.ExpiresAt);
                    }
                    if (tokenResult.ScopeList != null)
                    {
                        Console.WriteLine("Scopes: {0}", String.Join(" ", tokenResult.ScopeList));
                    }
                    Settings.Default.AccessToken = accessToken;
                    Settings.Default.Uid = uid;
                    Settings.Default.Save();
                    http.Stop();
                    return uid;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error: {0}", e.Message);
                    return null;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets information about the currently authorized account.
        /// <para>
        /// This demonstrates calling a simple rpc style api from the Users namespace.
        /// </para>
        /// </summary>
        /// <param name="client">The Dropbox client.</param>
        /// <returns>An asynchronous task.</returns>
        private async Task GetCurrentAccount(DropboxClient client)
        {
            try
            {
                Console.WriteLine("Current Account:");
                var full = await client.Users.GetCurrentAccountAsync();

                Console.WriteLine("Account id    : {0}", full.AccountId);
                Console.WriteLine("Country       : {0}", full.Country);
                Console.WriteLine("Email         : {0}", full.Email);
                Console.WriteLine("Is paired     : {0}", full.IsPaired ? "Yes" : "No");
                Console.WriteLine("Locale        : {0}", full.Locale);
                Console.WriteLine("Name");
                Console.WriteLine("  Display  : {0}", full.Name.DisplayName);
                Console.WriteLine("  Familiar : {0}", full.Name.FamiliarName);
                Console.WriteLine("  Given    : {0}", full.Name.GivenName);
                Console.WriteLine("  Surname  : {0}", full.Name.Surname);
                Console.WriteLine("Referral link : {0}", full.ReferralLink);

                if (full.Team != null)
                {
                    Console.WriteLine("Team");
                    Console.WriteLine("  Id   : {0}", full.Team.Id);
                    Console.WriteLine("  Name : {0}", full.Team.Name);
                }
                else
                {
                    Console.WriteLine("Team - None");
                }
            }
            catch (Exception e)
            {
                throw e;
            }

        }
    }
}

 

 

 

7 Replies 7

Greg-DB
Dropbox Staff

It looks like you're attempting to run the "OauthBasic" example from the Dropbox .NET SDK here. That's an example meant to show how a server-side app can process the OAuth app authorization flow to receive an access token and refresh token for making API calls.

 

I understand that can be tricky to set up from scratch, so I do recommend running that sample as provided without modifications first, other than plugging in your app key/secret and potentially different port number.

 

It sounds like you've done so, that is, are running the example unmodified except for app key/secret and port, and are receiving an error during the ProcessCodeFlowAsync call. Is that correct?

 

If so, can you show the full error you're getting? I would generally expect the error to contain more information than just that message, though you may need to inspect the exception object a bit. Feel free to share a screenshot if that would better illustrate what you're currently seeing. Thanks in advance!

Shy1
Explorer | Level 3
Spoiler
Помощник по отладке управляемого кода "DisconnectedContext" : "Переход к COM-контексту 0x7c6698 для данного объекта RuntimeCallableWrapper завершился следующей ошибкой: Исключение из HRESULT: 0xE0434352. Обычно это происходит из-за того, что COM-контекст 0x7c6698, в котором был создан этот объект RuntimeCallableWrapper, отключен или занят другой операцией. Выполняется освобождение интерфейсов из текущего COM-контекста (COM-контекст 0x7c6750). Это может привести к повреждению или потере данных. Для устранения этой проблемы убедитесь в том, что все контексты, подразделения и потоки будут существовать и оставаться доступными для перехода к контексту до полного завершения работы приложения с объектами RuntimeCallableWrapper, представляющими находящиеся в них COM-компоненты."

sorry for not english error if you believe the error, then it reports that the COM context is busy or disabled. 

and its was happen at the var redirectUri = await HandleJSRedirect(http); and next was catch the exception 

InnerException = {"The request was aborted: Failed to create SSL/TLS secure channel."}

StackTrace = " в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n в System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.Configur...

maybe I took the wrong example? maybe you can tell me how to connect to the API in an easier way? I’m not very strong in this, I practically don’t understand anything, I have an xamarin application that I would like to save the picture and download it when needed, maybe I approached the connection issue incorrectly or its correct way?

 

Shy1
Explorer | Level 3

if be clear OAthTest OAtestPCKE SimpleTest all code throw errors at about one moment, could it be that I didn’t set up something on the computer from not knowing? The problem is that if I manually go all the way through the browser then I get a response and I get the code in the browser window and I think if I copy it by hand and paste it into ReadLne it could work, but what am I doing wrong or what I have a problem, can I record a video of how I work with this?

Greg-DB
Dropbox Staff

I see you're getting an error "Failed to create SSL/TLS secure channel", which indicates your system wasn't able to establish a secure connection to the Dropbox API servers for the HTTPS requests needed to perform API calls. This may be because your system doesn't support a sufficient version of TLS.

 

For reference, Dropbox retired support for TLS 1.0 and 1.1 earlier this year. The Dropbox API servers now only support connections using TLS 1.2. You'll need to make sure your app/network client/environment support TLS 1.2 in order to continue making Dropbox API calls.

 
For your client/environment, please refer to the relevant documentation for information on enabling the relevant platform support. For example, Microsoft in particular appears to have some resources here which may be helpful:
 

Shy2
New member | Level 2

thanks for help! i just set the target 4.8 net and it work correclty

Shy2
New member | Level 2

how to close question? Or is there nothing else I need to do?

Greg-DB
Dropbox Staff

Thanks for following up. I'm glad to hear you got this working. No further action is required on your part for this thread.

Need more support?
Who's talking

Top contributors to this post

  • User avatar
    Greg-DB Dropbox Staff
  • User avatar
    Shy2 New member | Level 2
  • User avatar
    Shy1 Explorer | Level 3
What do Dropbox user levels mean?