@@ -44,8 +44,8 @@ private async Task<int> Run()
4444 Console . WriteLine ( "Example OAuth PKCE Application" ) ;
4545 DropboxCertHelper . InitializeCertPinning ( ) ;
4646
47- var uid = await AcquireOAuthTokens ( null , IncludeGrantedScopes . None ) ;
48- if ( string . IsNullOrEmpty ( uid ) )
47+ string accessToken = await GetOAuthTokens ( null , IncludeGrantedScopes . None ) ;
48+ if ( string . IsNullOrEmpty ( accessToken ) )
4949 {
5050 return 1 ;
5151 }
@@ -68,11 +68,8 @@ private async Task<int> Run()
6868 } ;
6969
7070 var client = new DropboxClient ( Settings . Default . RefreshToken , Settings . Default . ApiKey , config ) ;
71+ await GetCurrentAccount ( client ) ; // This call should succeed since the correct scope has been acquired
7172
72- // This call should succeed since the correct scope has been acquired
73- await GetCurrentAccount ( client ) ;
74-
75- Console . WriteLine ( "Oauth PKCE Test Complete!" ) ;
7673 Console . WriteLine ( "Exit with any key" ) ;
7774 Console . ReadKey ( ) ;
7875 }
@@ -90,6 +87,7 @@ private async Task<int> Run()
9087 return 0 ;
9188 }
9289
90+
9391 /// <summary>
9492 /// Handles the redirect from Dropbox server. Because we are using token flow, the local
9593 /// http server cannot directly receive the URL fragment. We need to return a HTML page with
@@ -135,9 +133,7 @@ private async Task<Uri> HandleJSRedirect(HttpListener http)
135133 context = await http . GetContextAsync ( ) ;
136134 }
137135
138- var redirectUri = new Uri ( context . Request . QueryString [ "url_with_fragment" ] ) ;
139-
140- return redirectUri ;
136+ return new Uri ( context . Request . QueryString [ "url_with_fragment" ] ) ;
141137 }
142138
143139 /// <summary>
@@ -148,8 +144,8 @@ private async Task<Uri> HandleJSRedirect(HttpListener http)
148144 /// displayed to authorize the user.
149145 /// </para>
150146 /// </summary>
151- /// <returns>A valid uid if a token was acquired or null.</returns>
152- private async Task < string > AcquireOAuthTokens ( string [ ] scopeList , IncludeGrantedScopes includeGrantedScopes )
147+ /// <returns>A valid access token if successful otherwise null.</returns>
148+ private async Task < string > GetOAuthTokens ( string [ ] scopeList , IncludeGrantedScopes includeGrantedScopes )
153149 {
154150 Settings . Default . Upgrade ( ) ;
155151 Console . Write ( "Reset settings (Y/N) " ) ;
@@ -159,32 +155,34 @@ private async Task<string> AcquireOAuthTokens(string[] scopeList, IncludeGranted
159155 }
160156 Console . WriteLine ( ) ;
161157
162- string accessToken = Settings . Default . AccessToken ;
163- string uid = Settings . Default . Uid ;
164-
165- if ( string . IsNullOrEmpty ( accessToken ) )
158+ if ( string . IsNullOrEmpty ( Settings . Default . AccessToken ) )
166159 {
167160 string apiKey = GetApiKey ( ) ;
168161
169162 using var http = new HttpListener ( ) ;
170163 try
171164 {
172- Console . WriteLine ( "Waiting for credentials." ) ;
173165 string state = Guid . NewGuid ( ) . ToString ( "N" ) ;
174166 var OAuthFlow = new PKCEOAuthFlow ( ) ;
175- var authorizeUri = OAuthFlow . GetAuthorizeUri ( OAuthResponseType . Code , apiKey , RedirectUri . ToString ( ) , state : state , tokenAccessType : TokenAccessType . Offline , scopeList : scopeList , includeGrantedScopes : includeGrantedScopes ) ;
167+ var authorizeUri = OAuthFlow . GetAuthorizeUri (
168+ OAuthResponseType . Code , apiKey , RedirectUri . ToString ( ) ,
169+ state : state , tokenAccessType : TokenAccessType . Offline ,
170+ scopeList : scopeList , includeGrantedScopes : includeGrantedScopes ) ;
171+
176172 http . Prefixes . Add ( LoopbackHost ) ;
177173
178174 http . Start ( ) ;
179175
176+ // Use StartInfo to ensure default browser launches.
180177 ProcessStartInfo startInfo = new ProcessStartInfo (
181- authorizeUri . ToString ( ) ) { UseShellExecute = true } ;
178+ authorizeUri . ToString ( ) )
179+ { UseShellExecute = true } ;
182180
183181 try
184182 {
185183 // open browser for authentication
184+ Console . WriteLine ( "Waiting for credentials and authorization." ) ;
186185 Process . Start ( startInfo ) ;
187- Console . WriteLine ( "Waiting for authentication..." ) ;
188186 }
189187 catch ( Exception )
190188 {
@@ -199,33 +197,24 @@ private async Task<string> AcquireOAuthTokens(string[] scopeList, IncludeGranted
199197
200198 http . Stop ( ) ;
201199
202- Console . WriteLine ( "Exchanging code for token" ) ;
203- var tokenResult = await OAuthFlow . ProcessCodeFlowAsync ( redirectUri , apiKey , RedirectUri . ToString ( ) , state ) ;
204- Console . WriteLine ( "Finished Exchanging Code for Token" ) ;
205- // Bring console window to the front.
206- SetForegroundWindow ( GetConsoleWindow ( ) ) ;
207- accessToken = tokenResult . AccessToken ;
208- string refreshToken = tokenResult . RefreshToken ;
209- uid = tokenResult . Uid ;
210- Console . WriteLine ( "Uid: {0}" , uid ) ;
211- Console . WriteLine ( "AccessToken: {0}" , accessToken ) ;
212- if ( tokenResult . RefreshToken != null )
200+ // Exchanging code for token
201+ var result = await OAuthFlow . ProcessCodeFlowAsync (
202+ redirectUri , apiKey , RedirectUri . ToString ( ) , state ) ;
203+ if ( result . State != state )
213204 {
214- Console . WriteLine ( "RefreshToken: {0}" , refreshToken ) ;
215- Settings . Default . RefreshToken = refreshToken ;
205+ // NOTE: Rightly or wrongly?, state is not returned or else
206+ // we would return null here.
207+ // See issue https://github.com/dropbox/dropbox-sdk-dotnet/issues/248
208+ Console . WriteLine ( "The state in the response doesn't match the state in the request." ) ;
216209 }
217- if ( tokenResult . ExpiresAt != null )
218- {
219- Console . WriteLine ( "ExpiresAt: {0}" , tokenResult . ExpiresAt ) ;
220- }
221- if ( tokenResult . ScopeList != null )
222- {
223- Console . WriteLine ( "Scopes: {0}" , String . Join ( " " , tokenResult . ScopeList ) ) ;
224- }
225- Settings . Default . AccessToken = accessToken ;
226- Settings . Default . Uid = uid ;
227- Settings . Default . Save ( ) ;
228- Settings . Default . Reload ( ) ;
210+ Console . WriteLine ( "OAuth token aquire complete" ) ;
211+
212+ // Bring console window to the front.
213+ SetForegroundWindow ( GetConsoleWindow ( ) ) ;
214+
215+ DisplayOAuthResult ( result ) ;
216+
217+ UpdateSettings ( result ) ;
229218 }
230219 catch ( Exception e )
231220 {
@@ -234,7 +223,32 @@ private async Task<string> AcquireOAuthTokens(string[] scopeList, IncludeGranted
234223 }
235224 }
236225
237- return uid ;
226+ return Settings . Default . AccessToken ;
227+ }
228+
229+ private static void UpdateSettings ( OAuth2Response result )
230+ {
231+ // Foreach Settting, save off the value retrieved from the result.
232+ foreach ( System . Configuration . SettingsProperty item in Settings . Default . Properties )
233+ {
234+ if ( typeof ( OAuth2Response ) . GetProperty ( item . Name ) is System . Reflection . PropertyInfo property )
235+ {
236+ Settings . Default [ item . Name ] = property . GetValue ( result ) ;
237+ }
238+ }
239+
240+ Settings . Default . Save ( ) ;
241+ Settings . Default . Reload ( ) ;
242+ }
243+
244+ private static void DisplayOAuthResult ( OAuth2Response result )
245+ {
246+ Console . WriteLine ( "OAuth Result:" ) ;
247+ Console . WriteLine ( "\t Uid: {0}" , result . Uid ) ;
248+ Console . WriteLine ( "\t AccessToken: {0}" , result . AccessToken ) ;
249+ Console . WriteLine ( "\t RefreshToken: {0}" , result . RefreshToken ) ;
250+ Console . WriteLine ( "\t ExpiresAt: {0}" , result . ExpiresAt ) ;
251+ Console . WriteLine ( "\t Scopes: {0}" , string . Join ( " " , result . ScopeList ?? new string [ 0 ] ) ) ;
238252 }
239253
240254 /// <summary>
@@ -273,41 +287,33 @@ private static string GetApiKey()
273287 /// </summary>
274288 /// <param name="client">The Dropbox client.</param>
275289 /// <returns>An asynchronous task.</returns>
276- private async Task GetCurrentAccount ( DropboxClient client )
290+ static private async Task GetCurrentAccount ( DropboxClient client )
277291 {
278- try
292+ Console . WriteLine ( "Current Account:" ) ;
293+ var full = await client . Users . GetCurrentAccountAsync ( ) ;
294+
295+ Console . WriteLine ( "Account id : {0}" , full . AccountId ) ;
296+ Console . WriteLine ( "Country : {0}" , full . Country ) ;
297+ Console . WriteLine ( "Email : {0}" , full . Email ) ;
298+ Console . WriteLine ( "Is paired : {0}" , full . IsPaired ? "Yes" : "No" ) ;
299+ Console . WriteLine ( "Locale : {0}" , full . Locale ) ;
300+ Console . WriteLine ( "Name" ) ;
301+ Console . WriteLine ( " Display : {0}" , full . Name . DisplayName ) ;
302+ Console . WriteLine ( " Familiar : {0}" , full . Name . FamiliarName ) ;
303+ Console . WriteLine ( " Given : {0}" , full . Name . GivenName ) ;
304+ Console . WriteLine ( " Surname : {0}" , full . Name . Surname ) ;
305+ Console . WriteLine ( "Referral link : {0}" , full . ReferralLink ) ;
306+
307+ if ( full . Team != null )
279308 {
280- Console . WriteLine ( "Current Account:" ) ;
281- var full = await client . Users . GetCurrentAccountAsync ( ) ;
282-
283- Console . WriteLine ( "Account id : {0}" , full . AccountId ) ;
284- Console . WriteLine ( "Country : {0}" , full . Country ) ;
285- Console . WriteLine ( "Email : {0}" , full . Email ) ;
286- Console . WriteLine ( "Is paired : {0}" , full . IsPaired ? "Yes" : "No" ) ;
287- Console . WriteLine ( "Locale : {0}" , full . Locale ) ;
288- Console . WriteLine ( "Name" ) ;
289- Console . WriteLine ( " Display : {0}" , full . Name . DisplayName ) ;
290- Console . WriteLine ( " Familiar : {0}" , full . Name . FamiliarName ) ;
291- Console . WriteLine ( " Given : {0}" , full . Name . GivenName ) ;
292- Console . WriteLine ( " Surname : {0}" , full . Name . Surname ) ;
293- Console . WriteLine ( "Referral link : {0}" , full . ReferralLink ) ;
294-
295- if ( full . Team != null )
296- {
297- Console . WriteLine ( "Team" ) ;
298- Console . WriteLine ( " Id : {0}" , full . Team . Id ) ;
299- Console . WriteLine ( " Name : {0}" , full . Team . Name ) ;
300- }
301- else
302- {
303- Console . WriteLine ( "Team - None" ) ;
304- }
309+ Console . WriteLine ( "Team" ) ;
310+ Console . WriteLine ( " Id : {0}" , full . Team . Id ) ;
311+ Console . WriteLine ( " Name : {0}" , full . Team . Name ) ;
305312 }
306- catch ( Exception e )
313+ else
307314 {
308- throw e ;
315+ Console . WriteLine ( "Team - None" ) ;
309316 }
310-
311317 }
312318 }
313319}
0 commit comments