Skip to content

Commit 23b8560

Browse files
qimingyuanQiming Yuan
authored andcommitted
Update console examples to use native browser for oauth2 flow.
1 parent c38ccc3 commit 23b8560

File tree

6 files changed

+176
-191
lines changed

6 files changed

+176
-191
lines changed

dropbox-sdk-dotnet/Dropbox.Api/DropboxOauth2Helper.cs

Lines changed: 63 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -40,64 +40,87 @@ public enum OAuthResponseType
4040
/// </summary>
4141
/// <example>
4242
/// <para>
43-
/// This shows an example of how to use the token, or implicit grant, flow.
44-
/// This code is part of a XAML window that contains a WebBrowser object as <c>this.Browser</c>
43+
/// This shows an example of how to use the token flow. This is part of a Windows Console or WPF app.
4544
/// </para>
4645
/// <para>
47-
/// The <c>Start</c> method calls <see cref="DropboxOAuth2Helper.GetAuthorizeUri" /> to create the URI that the browser component
48-
/// navigate to; the response type is set to <see cref="OAuthResponseType.Token"/> to create a URI for the token flow.
46+
/// The <c>GetAccessToken()</c> method calls <see cref="DropboxOAuth2Helper.GetAuthorizeUri" /> to create the URI with response type
47+
/// set to <see cref="OAuthResponseType.Token"/> for token flow.
4948
/// </para>
5049
/// <para>
51-
/// The exact value of the redirect URI is not important with the code flow, only that it is registered in the
52-
/// <a href="https://www.dropbox.com/developers/apps">App Console</a>; it is common to use a <c>localhost</c>
53-
/// URI for use within a client token flow like this.
50+
/// <see cref="Guid.NewGuid"/> is called to generate a random string to use as the state argument, this value can also be used to
51+
/// store application context and prevent cross-site request forgery.
5452
/// </para>
5553
/// <para>
56-
/// The <c>BrowserNavigating</c> method has been attached to the <c>Navigating</c> event on the <c>WebBrowser</c> object.
57-
/// It first checks if the URI to which the browser is navigating starts with the redirect uri provided in the call to
58-
/// <see cref="DropboxOAuth2Helper.GetAuthorizeUri" /> &#x2014; it is important not to prevent other navigation which may happen within the
59-
/// authorization flow &#x2014; if the URI matches, then the code uses <see cref="DropboxOAuth2Helper.ParseTokenFragment"/> to parse the
60-
/// <see cref="OAuth2Response"/> from the fragment component of the redirected URI. The <see cref="OAuth2Response.AccessToken" />
61-
/// will then be used to construct an instance of <see cref="DropboxClient"/>.
54+
/// A <see cref="HttpListener"/> is created to listen to the <c>RedirectUri</c> which will later receive redirect callback from
55+
/// the server. <see cref="System.Diagnostics.Process.Start"/> is called to launch a native browser and navigate user to the authorize
56+
/// URI. The <c>RedirectUri</c> needs to be registered at <a href="https://www.dropbox.com/developers/apps">App Console</a>. It's
57+
/// common to use value like <c>http://127.0.0.1:{some_avaialble_port}</c>.
58+
/// </para>
59+
/// <para>
60+
/// After user successfully authorizes the request, <c>HandleOAuth2Redirect</c> receives the redirect callback which contains state
61+
/// and access token as URL fragment. Since the server cannot receive URL fragment directly, it calls <c>RespondPageWithJSRedirect</c>
62+
/// to respond with a HTML page which runs JS code and sends URL fragment as query string parameter to a separate <c>JSRedirect</c> endpoint.
63+
/// </para>
64+
/// <para>
65+
/// <c>HandleJSRedirect</c> is called to handle redirect from JS code and processes OAuth response from query string.
66+
/// This returns an <see cref="OAuth2Response"/> containing the access token that will be passed to the <see cref="DropboxClient"/> constructor.
6267
/// </para>
6368
/// <code>
64-
/// private void Start(string appKey)
69+
/// private async Task HandleOAuth2Redirect(HttpListener http)
6570
/// {
66-
/// this.oauth2State = Guid.NewGuid().ToString("N");
67-
/// Uri authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OauthResponseType.Token, appKey, RedirectUri, state: oauth2State);
68-
/// this.Browser.Navigate(authorizeUri);
69-
/// }
71+
/// var context = await http.GetContextAsync();
7072
///
71-
/// private void BrowserNavigating(object sender, NavigatingCancelEventArgs e)
72-
/// {
73-
/// if (!e.Uri.ToString().StartsWith(RedirectUri, StringComparison.OrdinalIgnoreCase))
73+
/// // We only care about request to RedirectUri endpoint.
74+
/// while (context.Request.Url.AbsolutePath != RedirectUri.AbsolutePath)
7475
/// {
75-
/// // we need to ignore all navigation that isn't to the redirect uri.
76-
/// return;
76+
/// context = await http.GetContextAsync();
7777
/// }
7878
///
79-
/// try
80-
/// {
81-
/// OAuth2Response result = DropboxOAuth2Helper.ParseTokenFragment(e.Uri);
82-
/// if (result.State != this.oauth2State)
83-
/// {
84-
/// // The state in the response doesn't match the state in the request.
85-
/// return;
86-
/// }
79+
/// // Respond with a HTML page which runs JS to send URl fragment.
80+
/// RespondPageWithJSRedirect();
81+
/// }
8782
///
88-
/// this.AccessToken = result.AccessToken;
89-
/// this.Uid = result.Uid;
90-
/// this.Result = true;
91-
/// }
92-
/// catch (ArgumentException)
83+
///
84+
/// private async Task&lt;OAuth2Response&gt; HandleJSRedirect(HttpListener http)
85+
/// {
86+
/// var context = await http.GetContextAsync();
87+
///
88+
/// // We only care about request to TokenRedirectUri endpoint.
89+
/// while (context.Request.Url.AbsolutePath != JSRedirectUri.AbsolutePath)
9390
/// {
94-
/// // There was an error in the URI passed to ParseTokenFragment
91+
/// context = await http.GetContextAsync();
9592
/// }
96-
/// finally
93+
///
94+
/// var redirectUri = new Uri(context.Request.QueryString["url_with_fragment"]);
95+
///
96+
/// var result = DropboxOAuth2Helper.ParseTokenFragment(redirectUri);
97+
///
98+
/// return result;
99+
/// }
100+
///
101+
/// private async Task GetAccessToken() {
102+
/// var state = Guid.NewGuid().ToString("N");
103+
/// var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Code, ApiKey, new Uri(RedirectUri), state: state);
104+
///
105+
/// var http = new HttpListener();
106+
/// http.Prefixes.Add(RedirectUri);
107+
/// http.Start();
108+
///
109+
/// System.Diagnostics.Process.Start(authorizeUri.ToString());
110+
///
111+
/// // Handle OAuth redirect and send URL fragment to local server using JS.
112+
/// await HandleOAuth2Redirect(http);
113+
///
114+
/// // Handle redirect from JS and process OAuth response.
115+
/// var result = await HandleJSRedirect(http);
116+
///
117+
/// if (result.State != state)
97118
/// {
98-
/// e.Cancel = true;
99-
/// this.Close();
119+
/// // The state in the response doesn't match the state in the request.
120+
/// return null;
100121
/// }
122+
///
123+
/// Settings.Default.AccessToken = result.AccessToken;
101124
/// }
102125
/// </code>
103126
/// <para>

dropbox-sdk-dotnet/Examples/SimpleTest/LoginForm.xaml

Lines changed: 0 additions & 23 deletions
This file was deleted.

dropbox-sdk-dotnet/Examples/SimpleTest/LoginForm.xaml.cs

Lines changed: 0 additions & 86 deletions
This file was deleted.

0 commit comments

Comments
 (0)