LEFT | RIGHT |
1 /* | 1 /* |
2 Copyright 2013 Google Inc | 2 Copyright 2013 Google Inc |
3 | 3 |
4 Licensed under the Apache License, Version 2.0 (the "License"); | 4 Licensed under the Apache License, Version 2.0 (the "License"); |
5 you may not use this file except in compliance with the License. | 5 you may not use this file except in compliance with the License. |
6 You may obtain a copy of the License at | 6 You may obtain a copy of the License at |
7 | 7 |
8 http://www.apache.org/licenses/LICENSE-2.0 | 8 http://www.apache.org/licenses/LICENSE-2.0 |
9 | 9 |
10 Unless required by applicable law or agreed to in writing, software | 10 Unless required by applicable law or agreed to in writing, software |
11 distributed under the License is distributed on an "AS IS" BASIS, | 11 distributed under the License is distributed on an "AS IS" BASIS, |
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 See the License for the specific language governing permissions and | 13 See the License for the specific language governing permissions and |
14 limitations under the License. | 14 limitations under the License. |
15 */ | 15 */ |
16 | 16 |
17 using System; | 17 using System; |
18 using System.Collections.Generic; | 18 using System.Collections.Generic; |
19 using System.IO; | 19 using System.IO; |
20 using System.Net.Http; | 20 using System.Net.Http; |
21 using System.Threading; | 21 using System.Threading; |
22 using System.Threading.Tasks; | 22 using System.Threading.Tasks; |
23 | 23 |
24 using Google.Apis.Auth.OAuth2.Requests; | 24 using Google.Apis.Auth.OAuth2.Requests; |
25 using Google.Apis.Auth.OAuth2.Responses; | 25 using Google.Apis.Auth.OAuth2.Responses; |
26 using Google.Apis.Http; | 26 using Google.Apis.Http; |
27 using Google.Apis.Json; | |
28 using Google.Apis.Logging; | 27 using Google.Apis.Logging; |
29 using Google.Apis.Requests.Parameters; | |
30 using Google.Apis.Util; | 28 using Google.Apis.Util; |
31 using Google.Apis.Util.Store; | 29 using Google.Apis.Util.Store; |
32 using Google.Apis.Testing; | 30 using Google.Apis.Testing; |
33 | 31 |
34 namespace Google.Apis.Auth.OAuth2 | 32 namespace Google.Apis.Auth.OAuth2 |
35 { | 33 { |
36 /// <summary> | 34 /// <summary> |
37 /// Thread-safe OAuth 2.0 authorization code flow that manages and persists
end-user credentials. | 35 /// Thread-safe OAuth 2.0 authorization code flow that manages and persists
end-user credentials. |
38 /// <para> | 36 /// <para> |
39 /// This is designed to simplify the flow in which an end-user authorizes th
e application to access their protected | 37 /// This is designed to simplify the flow in which an end-user authorizes th
e application to access their protected |
40 /// data, and then the application has access to their data based on an acce
ss token and a refresh token to refresh· | 38 /// data, and then the application has access to their data based on an acce
ss token and a refresh token to refresh· |
41 /// that access token when it expires. | 39 /// that access token when it expires. |
42 /// </para> | 40 /// </para> |
43 /// </summary> | 41 /// </summary> |
44 public class AuthorizationCodeFlow : IAuthorizationCodeFlow | 42 public class AuthorizationCodeFlow : IAuthorizationCodeFlow |
45 { | 43 { |
46 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy
pe<AuthorizationCodeFlow>(); | 44 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy
pe<AuthorizationCodeFlow>(); |
47 | 45 |
48 #region Initializer | 46 #region Initializer |
49 | 47 |
50 /// <summary>An initializer class for the authorization code flow. </sum
mary> | 48 /// <summary>An initializer class for the authorization code flow. </sum
mary> |
51 public class Initializer | 49 public class Initializer |
52 { | 50 { |
53 /// <summary> | 51 /// <summary> |
54 /// Gets or sets the method for presenting the access token to the r
esource server. | 52 /// Gets or sets the method for presenting the access token to the r
esource server. |
55 /// The default value is <seealso cref="BearerToken.AuthorizationHea
derAccessMethod"/>. | 53 /// The default value is <seealso cref="BearerToken.AuthorizationHea
derAccessMethod"/>. |
56 /// </summary> | 54 /// </summary> |
57 public IAccessMethod AccessMethod { get; set; } | 55 public IAccessMethod AccessMethod { get; set; } |
58 | 56 |
59 /// <summary>Gets or sets the token server URL.</summary> | 57 /// <summary>Gets the token server URL.</summary> |
60 public string TokenServerUrl { get; private set; } | 58 public string TokenServerUrl { get; private set; } |
61 | 59 |
62 /// <summary>Gets or sets the authorization server URL.</summary> | 60 /// <summary>Gets or sets the authorization server URL.</summary> |
63 public string AuthorizationServerUrl { get; private set; } | 61 public string AuthorizationServerUrl { get; private set; } |
64 | 62 |
65 /// <summary>Gets or sets the client secrets which includes the clie
nt identifier and its secret.</summary> | 63 /// <summary>Gets or sets the client secrets which includes the clie
nt identifier and its secret.</summary> |
66 public ClientSecrets ClientSecrets { get; set; } | 64 public ClientSecrets ClientSecrets { get; set; } |
67 | 65 |
68 /// <summary> | 66 /// <summary> |
69 /// Gets or sets the client secrets stream which contains the client
identifier and its secret. | 67 /// Gets or sets the client secrets stream which contains the client
identifier and its secret. |
70 /// </summary> | 68 /// </summary> |
71 /// <remarks>The AuthorizationCodeFlow constructor is responsible fo
r disposing the stream.</remarks> | 69 /// <remarks>The AuthorizationCodeFlow constructor is responsible fo
r disposing the stream.</remarks> |
72 public Stream ClientSecretsStream { get; set; } | 70 public Stream ClientSecretsStream { get; set; } |
73 | 71 |
74 /// <summary>Gets or sets the data store used to store the credentia
l.</summary> | 72 /// <summary>Gets or sets the data store used to store the token res
ponse.</summary> |
75 public IDataStore DataStore { get; set; } | 73 public IDataStore DataStore { get; set; } |
76 | 74 |
77 /// <summary>Gets or sets the scopes.</summary> | 75 /// <summary> |
| 76 /// Gets or sets the scopes which indicate the API access your appli
cation is requesting. |
| 77 /// </summary> |
78 public IEnumerable<string> Scopes { get; set; } | 78 public IEnumerable<string> Scopes { get; set; } |
79 | 79 |
80 /// <summary>· | 80 /// <summary>· |
81 /// Gets or sets the factory for creating <see cref="System.Net.Http
.HttpClient"/> instance. | 81 /// Gets or sets the factory for creating <see cref="System.Net.Http
.HttpClient"/> instance. |
82 /// </summary> | 82 /// </summary> |
83 public IHttpClientFactory HttpClientFactory { get; set; } | 83 public IHttpClientFactory HttpClientFactory { get; set; } |
84 | 84 |
85 /// <summary> | 85 /// <summary> |
86 /// Get or sets the exponential back-off policy. Default value is <
c>UnsuccessfulResponse503</c>, which· | 86 /// Get or sets the exponential back-off policy. Default value is <
c>UnsuccessfulResponse503</c>, which· |
87 /// means that exponential back-off is used on 503 abnormal HTTP res
ponses. | 87 /// means that exponential back-off is used on 503 abnormal HTTP res
ponses. |
88 /// If the value is set to <c>None</c>, no exponential back-off poli
cy is used, and it's up to user to | 88 /// If the value is set to <c>None</c>, no exponential back-off poli
cy is used, and it's up to user to |
89 /// configure the <seealso cref="Google.Apis.Http.ConfigurableMessag
eHandler"/> in an | 89 /// configure the <seealso cref="Google.Apis.Http.ConfigurableMessag
eHandler"/> in an |
90 /// <seealso cref="Google.Apis.Http.IConfigurableHttpClientInitializ
er"/> to set a specific back-off | 90 /// <seealso cref="Google.Apis.Http.IConfigurableHttpClientInitializ
er"/> to set a specific back-off |
91 /// implementation (using <seealso cref="Google.Apis.Http.BackOffHan
dler"/>). | 91 /// implementation (using <seealso cref="Google.Apis.Http.BackOffHan
dler"/>). |
92 /// </summary> | 92 /// </summary> |
93 public ExponentialBackOffPolicy DefaultExponentialBackOffPolicy { ge
t; set; } | 93 public ExponentialBackOffPolicy DefaultExponentialBackOffPolicy { ge
t; set; } |
94 | 94 |
95 /// <summary> | 95 /// <summary> |
96 /// Gets or sets the clock. The clock is used to determine if the to
ken has expired, if so we will try | 96 /// Gets or sets the clock. The clock is used to determine if the to
ken has expired, if so we will try to |
97 /// to refresh it. | 97 /// refresh it. The default value is <seealso cref="SystemClock.Defa
ult"/>. |
98 /// Default value is <seealso cref="SystemClock.Default"/>. | |
99 /// </summary> | 98 /// </summary> |
100 public IClock Clock { get; set; } | 99 public IClock Clock { get; set; } |
101 | 100 |
102 /// <summary>Constructs a new initializer.</summary> | 101 /// <summary>Constructs a new initializer.</summary> |
103 /// <param name="authorizationServerUrl">Authorization server URL</p
aram> | 102 /// <param name="authorizationServerUrl">Authorization server URL</p
aram> |
104 /// <param name="tokenServerUrl">Token server URL</param> | 103 /// <param name="tokenServerUrl">Token server URL</param> |
105 public Initializer(string authorizationServerUrl, string tokenServer
Url) | 104 public Initializer(string authorizationServerUrl, string tokenServer
Url) |
106 { | 105 { |
107 AuthorizationServerUrl = authorizationServerUrl; | 106 AuthorizationServerUrl = authorizationServerUrl; |
108 TokenServerUrl = tokenServerUrl; | 107 TokenServerUrl = tokenServerUrl; |
(...skipping 14 matching lines...) Expand all Loading... |
123 private readonly string authorizationServerUrl; | 122 private readonly string authorizationServerUrl; |
124 private readonly ClientSecrets clientSecrets; | 123 private readonly ClientSecrets clientSecrets; |
125 private readonly IDataStore dataStore; | 124 private readonly IDataStore dataStore; |
126 private readonly IEnumerable<string> scopes; | 125 private readonly IEnumerable<string> scopes; |
127 private readonly ConfigurableHttpClient httpClient; | 126 private readonly ConfigurableHttpClient httpClient; |
128 private readonly IClock clock; | 127 private readonly IClock clock; |
129 | 128 |
130 #endregion | 129 #endregion |
131 | 130 |
132 /// <summary>Gets the token server URL.</summary> | 131 /// <summary>Gets the token server URL.</summary> |
133 public string TokenServerEncodedUrl { get { return tokenServerUrl; } } | 132 public string TokenServerUrl { get { return tokenServerUrl; } } |
134 | 133 |
135 /// <summary>Gets the authorization code server URL.</summary> | 134 /// <summary>Gets the authorization code server URL.</summary> |
136 public string AuthorizationServerUrl { get { return authorizationServerU
rl; } } | 135 public string AuthorizationServerUrl { get { return authorizationServerU
rl; } } |
137 | 136 |
138 /// <summary>Gets the client secrets which includes the client identifie
r and its secret.</summary> | 137 /// <summary>Gets the client secrets which includes the client identifie
r and its secret.</summary> |
139 public ClientSecrets ClientSecrets { get { return clientSecrets; } } | 138 public ClientSecrets ClientSecrets { get { return clientSecrets; } } |
140 | 139 |
141 /// <summary>Gets the data store used to store the credentials.</summary
> | 140 /// <summary>Gets the data store used to store the credentials.</summary
> |
142 public IDataStore DataStore { get { return dataStore; } } | 141 public IDataStore DataStore { get { return dataStore; } } |
143 | 142 |
144 /// <summary>Gets the scopes.</summary> | 143 /// <summary>Gets the scopes which indicate the API access your applicat
ion is requesting.</summary> |
145 public IEnumerable<string> Scopes { get { return scopes; } } | 144 public IEnumerable<string> Scopes { get { return scopes; } } |
146 | 145 |
147 /// <summary>Gets the HTTP client used to make authentication requests t
o the server.</summary> | 146 /// <summary>Gets the HTTP client used to make authentication requests t
o the server.</summary> |
148 public ConfigurableHttpClient HttpClient { get { return httpClient; } } | 147 public ConfigurableHttpClient HttpClient { get { return httpClient; } } |
149 | 148 |
150 /// <summary>Constructs a new flow using the initializer's properties.</
summary> | 149 /// <summary>Constructs a new flow using the initializer's properties.</
summary> |
151 public AuthorizationCodeFlow(Initializer initializer) | 150 public AuthorizationCodeFlow(Initializer initializer) |
152 { | 151 { |
153 clientSecrets = initializer.ClientSecrets; | 152 clientSecrets = initializer.ClientSecrets; |
154 if (clientSecrets == null) | 153 if (clientSecrets == null) |
155 { | 154 { |
156 if (initializer.ClientSecretsStream == null) | 155 if (initializer.ClientSecretsStream == null) |
157 { | 156 { |
158 throw new ArgumentException( | 157 throw new ArgumentException("You MUST set ClientSecret or Cl
ientSecretStream on the initializer"); |
159 "At least one of the client secret or client secret stre
am MUST be set"); | |
160 } | 158 } |
161 | 159 |
162 try | 160 using (initializer.ClientSecretsStream) |
163 { | 161 { |
164 using (initializer.ClientSecretsStream) | 162 clientSecrets = GoogleClientSecrets.Load(initializer.ClientS
ecretsStream).Secrets; |
165 { | |
166 clientSecrets = GoogleClientSecrets.Load(initializer.Cli
entSecretsStream).Secrets; | |
167 } | |
168 } | 163 } |
169 catch (Exception ex) | 164 } |
170 { | 165 |
171 throw new ArgumentException("Can't read the client secrets f
rom the given stream", ex); | 166 accessMethod = initializer.AccessMethod.ThrowIfNull("Initializer.Acc
essMethod"); |
172 } | 167 clock = initializer.Clock.ThrowIfNull("Initializer.Clock"); |
173 } | 168 tokenServerUrl = initializer.TokenServerUrl.ThrowIfNullOrEmpty("Init
ializer.TokenServerUrl"); |
174 initializer.AccessMethod.ThrowIfNull("AccessMethod"); | |
175 initializer.ClientSecrets.ThrowIfNull("Clock"); | |
176 | |
177 accessMethod = initializer.AccessMethod; | |
178 tokenServerUrl = initializer.TokenServerUrl.ThrowIfNullOrEmpty("Toke
nServerUrl"); | |
179 authorizationServerUrl = initializer.AuthorizationServerUrl.ThrowIfN
ullOrEmpty | 169 authorizationServerUrl = initializer.AuthorizationServerUrl.ThrowIfN
ullOrEmpty |
180 ("AuthorizationServerUrl"); | 170 ("Initializer.AuthorizationServerUrl"); |
181 clock = initializer.Clock; | |
182 | 171 |
183 dataStore = initializer.DataStore; | 172 dataStore = initializer.DataStore; |
184 if (dataStore == null) | 173 if (dataStore == null) |
185 { | 174 { |
186 Logger.Warning("Datastore is null, as a result the user's creden
tial will not be stored"); | 175 Logger.Warning("Datastore is null, as a result the user's creden
tial will not be stored"); |
187 } | 176 } |
188 scopes = initializer.Scopes; | 177 scopes = initializer.Scopes; |
189 | 178 |
190 // Set the HTTP client. | 179 // Set the HTTP client. |
191 var httpArgs = new CreateHttpClientArgs(); | 180 var httpArgs = new CreateHttpClientArgs(); |
192 | 181 |
193 // Add exponential back-off initializer if necessary. | 182 // Add exponential back-off initializer if necessary. |
194 if (initializer.DefaultExponentialBackOffPolicy != ExponentialBackOf
fPolicy.None) | 183 if (initializer.DefaultExponentialBackOffPolicy != ExponentialBackOf
fPolicy.None) |
195 { | 184 { |
196 httpArgs.Initializers.Add( | 185 httpArgs.Initializers.Add( |
197 new ExponentialBackOffInitializer(initializer.DefaultExponen
tialBackOffPolicy, | 186 new ExponentialBackOffInitializer(initializer.DefaultExponen
tialBackOffPolicy, |
198 () => new BackOffHandler(new ExponentialBackOff()))); | 187 () => new BackOffHandler(new ExponentialBackOff()))); |
199 } | 188 } |
200 httpClient = (initializer.HttpClientFactory ?? new HttpClientFactory
()).CreateHttpClient(httpArgs); | 189 httpClient = (initializer.HttpClientFactory ?? new HttpClientFactory
()).CreateHttpClient(httpArgs); |
201 } | 190 } |
202 | 191 |
203 #region IAuthorizationCodeFlow overrides | 192 #region IAuthorizationCodeFlow overrides |
204 | 193 |
205 public IAccessMethod AccessMethod { get { return accessMethod; } } | 194 public IAccessMethod AccessMethod { get { return accessMethod; } } |
206 | 195 |
207 public IClock Clock { get { return clock; } } | 196 public IClock Clock { get { return clock; } } |
208 | 197 |
209 public async Task<TokenResponse> LoadToken(string userId, CancellationTo
ken taskCancellationToken) | 198 public async Task<TokenResponse> LoadTokenAsync(string userId, Cancellat
ionToken taskCancellationToken) |
210 { | 199 { |
211 taskCancellationToken.ThrowIfCancellationRequested(); | 200 taskCancellationToken.ThrowIfCancellationRequested(); |
212 if (DataStore == null) | 201 if (DataStore == null) |
213 { | 202 { |
214 return null; | 203 return null; |
215 } | 204 } |
216 return await DataStore.Get<TokenResponse>(userId).ConfigureAwait(fal
se); | 205 return await DataStore.GetAsync<TokenResponse>(userId).ConfigureAwai
t(false); |
217 } | 206 } |
218 | 207 |
219 public async Task DeleteToken(string userId, CancellationToken taskCance
llationToken) | 208 public async Task DeleteTokenAsync(string userId, CancellationToken task
CancellationToken) |
220 { | 209 { |
221 taskCancellationToken.ThrowIfCancellationRequested(); | 210 taskCancellationToken.ThrowIfCancellationRequested(); |
222 if (DataStore != null) | 211 if (DataStore != null) |
223 { | 212 { |
224 await DataStore.Delete<TokenResponse>(userId).ConfigureAwait(fal
se); | 213 await DataStore.DeleteAsync<TokenResponse>(userId).ConfigureAwai
t(false); |
225 } | 214 } |
226 } | 215 } |
227 | 216 |
228 public virtual AuthorizationCodeRequestUrl CreateAuthorizationCodeReques
t(string redirectUri) | 217 public virtual AuthorizationCodeRequestUrl CreateAuthorizationCodeReques
t(string redirectUri) |
229 { | 218 { |
230 return new AuthorizationCodeRequestUrl(new Uri(AuthorizationServerUr
l)) | 219 return new AuthorizationCodeRequestUrl(new Uri(AuthorizationServerUr
l)) |
231 { | 220 { |
232 ClientId = ClientSecrets.ClientId, | 221 ClientId = ClientSecrets.ClientId, |
233 Scope = string.Join(" ", Scopes), | 222 Scope = string.Join(" ", Scopes), |
234 RedirectUri = redirectUri | 223 RedirectUri = redirectUri |
235 }; | 224 }; |
236 } | 225 } |
237 | 226 |
238 public async Task<TokenResponse> ExchangeCodeForToken(string userId, str
ing code, string redirectUri, | 227 public async Task<TokenResponse> ExchangeCodeForTokenAsync(string userId
, string code, string redirectUri, |
239 CancellationToken taskCancellationToken) | 228 CancellationToken taskCancellationToken) |
240 { | 229 { |
241 taskCancellationToken.ThrowIfCancellationRequested(); | |
242 var authorizationCodeTokenReq = new AuthorizationCodeTokenRequest | 230 var authorizationCodeTokenReq = new AuthorizationCodeTokenRequest |
243 { | 231 { |
244 Scope = string.Join(" ", Scopes), | 232 Scope = string.Join(" ", Scopes), |
245 RedirectUri = redirectUri, | 233 RedirectUri = redirectUri, |
246 Code = code, | 234 Code = code, |
247 }; | 235 }; |
248 | 236 |
249 var token = await FetchToken(userId, authorizationCodeTokenReq, task
CancellationToken).ConfigureAwait(false); | 237 var token = await FetchTokenAsync(userId, authorizationCodeTokenReq,
taskCancellationToken) |
250 await StoreToken(userId, token, taskCancellationToken).ConfigureAwai
t(false); | 238 .ConfigureAwait(false); |
| 239 await StoreTokenAsync(userId, token, taskCancellationToken).Configur
eAwait(false); |
251 return token; | 240 return token; |
252 } | 241 } |
253 | 242 |
254 public async Task<TokenResponse> RefreshToken(string userId, string refr
eshToken, | 243 public async Task<TokenResponse> RefreshTokenAsync(string userId, string
refreshToken, |
255 CancellationToken taskCancellationToken) | 244 CancellationToken taskCancellationToken) |
256 { | 245 { |
257 taskCancellationToken.ThrowIfCancellationRequested(); | |
258 var refershTokenReq = new RefreshTokenRequest | 246 var refershTokenReq = new RefreshTokenRequest |
259 { | 247 { |
260 RefreshToken = refreshToken, | 248 RefreshToken = refreshToken, |
261 }; | 249 }; |
262 var token = await FetchToken(userId, refershTokenReq, taskCancellati
onToken).ConfigureAwait(false); | 250 var token = await FetchTokenAsync(userId, refershTokenReq, taskCance
llationToken).ConfigureAwait(false); |
263 | 251 |
264 // The new token doesn't contain a refresh token, so set it with the
given refresh token. | 252 // The new token may not contain a refresh token, so set it with the
given refresh token. |
265 if (token.RefreshToken == null) | 253 if (token.RefreshToken == null) |
266 { | 254 { |
267 token.RefreshToken = refreshToken; | 255 token.RefreshToken = refreshToken; |
268 } | 256 } |
269 | 257 |
270 await StoreToken(userId, token, taskCancellationToken).ConfigureAwai
t(false); | 258 await StoreTokenAsync(userId, token, taskCancellationToken).Configur
eAwait(false); |
271 return token; | 259 return token; |
272 } | 260 } |
273 | 261 |
274 #endregion | 262 #endregion |
275 | 263 |
276 /// <summary>Stores the token in the <see cref="DataStore"/>.</summary> | 264 /// <summary>Stores the token in the <see cref="DataStore"/>.</summary> |
277 /// <param name="userId">User identifier</param> | 265 /// <param name="userId">User identifier</param> |
278 /// <param name="token">Token to store</param> | 266 /// <param name="token">Token to store</param> |
279 /// <param name="taskCancellationToken">Cancellation token to cancel ope
ration</param> | 267 /// <param name="taskCancellationToken">Cancellation token to cancel ope
ration</param> |
280 private async Task StoreToken(string userId, TokenResponse token, Cancel
lationToken taskCancellationToken) | 268 private async Task StoreTokenAsync(string userId, TokenResponse token, C
ancellationToken taskCancellationToken) |
281 { | 269 { |
282 taskCancellationToken.ThrowIfCancellationRequested(); | 270 taskCancellationToken.ThrowIfCancellationRequested(); |
283 if (DataStore != null) | 271 if (DataStore != null) |
284 { | 272 { |
285 await DataStore.Store<TokenResponse>(userId, token).ConfigureAwa
it(false); | 273 await DataStore.StoreAsync<TokenResponse>(userId, token).Configu
reAwait(false); |
286 } | 274 } |
287 } | 275 } |
288 | 276 |
289 /// <summary>Retrieve a new token from the server using the specified re
quest.</summary> | 277 /// <summary>Retrieve a new token from the server using the specified re
quest.</summary> |
290 /// <param name="userId">User identifier</param> | 278 /// <param name="userId">User identifier</param> |
291 /// <param name="request">Token request</param> | 279 /// <param name="request">Token request</param> |
292 /// <param name="taskCancellationToken">Cancellation token to cancel ope
ration</param> | 280 /// <param name="taskCancellationToken">Cancellation token to cancel ope
ration</param> |
293 /// <returns>Token response with the new access token</returns> | 281 /// <returns>Token response with the new access token</returns> |
294 [VisibleForTestOnly] | 282 [VisibleForTestOnly] |
295 internal async Task<TokenResponse> FetchToken(string userId, TokenReques
t request, | 283 internal async Task<TokenResponse> FetchTokenAsync(string userId, TokenR
equest request, |
296 CancellationToken taskCancellationToken) | 284 CancellationToken taskCancellationToken) |
297 { | 285 { |
298 // Add client id and client secret to requests. | 286 // Add client id and client secret to requests. |
299 request.ClientId = ClientSecrets.ClientId; | 287 request.ClientId = ClientSecrets.ClientId; |
300 request.ClientSecret = ClientSecrets.ClientSecret; | 288 request.ClientSecret = ClientSecrets.ClientSecret; |
301 | 289 |
302 var httpRequest = new HttpRequestMessage(HttpMethod.Post, TokenServe
rEncodedUrl); | 290 TokenResponseException tokenException = null; |
303 httpRequest.Content = ParameterUtils.CreateFormUrlEncodedContent(req
uest); | 291 try |
304 | 292 { |
305 var response = await HttpClient.SendAsync(httpRequest, taskCancellat
ionToken).ConfigureAwait(false); | 293 var tokenResponse = await request.Execute(httpClient, TokenServe
rUrl, taskCancellationToken, Clock); |
306 | 294 return tokenResponse; |
307 taskCancellationToken.ThrowIfCancellationRequested(); | 295 } |
308 | 296 catch (TokenResponseException ex) |
309 if (!response.IsSuccessStatusCode) | 297 { |
310 { | 298 // In case there is an exception during getting the token, we de
lete any user's token information from· |
311 var error = NewtonsoftJsonSerializer.Instance.Deserialize<TokenE
rrorResponse>( | 299 // the data store. |
312 await response.Content.ReadAsStringAsync().ConfigureAwait(fa
lse)); | 300 tokenException = ex; |
313 | 301 } |
314 await DeleteToken(userId, taskCancellationToken); | 302 await DeleteTokenAsync(userId, taskCancellationToken); |
315 | 303 throw tokenException; |
316 throw new TokenResponseException(error); | |
317 } | |
318 | |
319 // gets the token and sets its issued time | |
320 var token = NewtonsoftJsonSerializer.Instance.Deserialize<TokenRespo
nse>( | |
321 await response.Content.ReadAsStringAsync().ConfigureAwait(false)
); | |
322 token.Issued = clock.Now; | |
323 | |
324 return token; | |
325 } | 304 } |
326 | 305 |
327 public void Dispose() | 306 public void Dispose() |
328 { | 307 { |
329 if (HttpClient != null) | 308 if (HttpClient != null) |
330 { | 309 { |
331 HttpClient.Dispose(); | 310 HttpClient.Dispose(); |
332 } | 311 } |
333 } | 312 } |
334 } | 313 } |
335 } | 314 } |
LEFT | RIGHT |