Skip to content

Commit 4933dea

Browse files
committed
Added support for proxy configs in auth flows, closes #360
1 parent 0a9499c commit 4933dea

File tree

5 files changed

+63
-45
lines changed

5 files changed

+63
-45
lines changed

SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ namespace SpotifyAPI.Web.Auth
1515
public class AuthorizationCodeAuth : SpotifyAuthServer<AuthorizationCode>
1616
{
1717
public string SecretId { get; set; }
18+
19+
public ProxyConfig ProxyConfig { get; set; }
1820

1921
public AuthorizationCodeAuth(string redirectUri, string serverUri, Scope scope = Scope.None, string state = "")
2022
: base("code", "AuthorizationCodeAuth", redirectUri, serverUri, scope, state)
@@ -53,7 +55,8 @@ public async Task<Token> RefreshToken(string refreshToken)
5355
new KeyValuePair<string, string>("refresh_token", refreshToken)
5456
};
5557

56-
HttpClient client = new HttpClient();
58+
HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig);
59+
HttpClient client = new HttpClient(handler);
5760
client.DefaultRequestHeaders.Add("Authorization", GetAuthHeader());
5861
HttpContent content = new FormUrlEncodedContent(args);
5962

SpotifyAPI.Web.Auth/CredentialsAuth.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public class CredentialsAuth
1313
public string ClientSecret { get; set; }
1414

1515
public string ClientId { get; set; }
16+
17+
public ProxyConfig ProxyConfig { get; set; }
1618

1719
public CredentialsAuth(string clientId, string clientSecret)
1820
{
@@ -29,7 +31,8 @@ public async Task<Token> GetToken()
2931
new KeyValuePair<string, string>("grant_type", "client_credentials")
3032
};
3133

32-
HttpClient client = new HttpClient();
34+
HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig);
35+
HttpClient client = new HttpClient(handler);
3336
client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}");
3437
HttpContent content = new FormUrlEncodedContent(args);
3538

SpotifyAPI.Web.Auth/TokenSwapAuth.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,34 @@ namespace SpotifyAPI.Web.Auth
2222
/// </summary>
2323
public class TokenSwapAuth : SpotifyAuthServer<AuthorizationCode>
2424
{
25-
string exchangeServerUri;
25+
readonly string _exchangeServerUri;
2626

2727
/// <summary>
2828
/// The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival.
2929
/// </summary>
3030
public string HtmlResponse { get; set; } = "<script>window.close();</script>";
31+
3132
/// <summary>
3233
/// If true, will time how long it takes for access to expire. On expiry, the <see cref="OnAccessTokenExpired"/> event fires.
3334
/// </summary>
3435
public bool TimeAccessExpiry { get; set; }
3536

37+
public ProxyConfig ProxyConfig { get; set; }
38+
3639
/// <param name="exchangeServerUri">The URI to an exchange server that will perform the key exchange.</param>
3740
/// <param name="serverUri">The URI to host the server at that your exchange server should return the authorization code to by GET request. (e.g. http://localhost:4002)</param>
3841
/// <param name="scope"></param>
3942
/// <param name="state">Stating none will randomly generate a state parameter.</param>
4043
/// <param name="htmlResponse">The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival.</param>
41-
public TokenSwapAuth(string exchangeServerUri, string serverUri, Scope scope = Scope.None, string state = "", string htmlResponse = "") : base("code", "", "", serverUri, scope, state)
44+
public TokenSwapAuth(string exchangeServerUri, string serverUri, Scope scope = Scope.None, string state = "",
45+
string htmlResponse = "") : base("code", "", "", serverUri, scope, state)
4246
{
4347
if (!string.IsNullOrEmpty(htmlResponse))
4448
{
4549
HtmlResponse = htmlResponse;
4650
}
4751

48-
this.exchangeServerUri = exchangeServerUri;
52+
_exchangeServerUri = exchangeServerUri;
4953
}
5054

5155
protected override void AdaptWebServer(WebServer webServer)
@@ -55,7 +59,7 @@ protected override void AdaptWebServer(WebServer webServer)
5559

5660
public override string GetUri()
5761
{
58-
StringBuilder builder = new StringBuilder(exchangeServerUri);
62+
StringBuilder builder = new StringBuilder(_exchangeServerUri);
5963
builder.Append("?");
6064
builder.Append("response_type=code");
6165
builder.Append("&state=" + State);
@@ -64,8 +68,6 @@ public override string GetUri()
6468
return Uri.EscapeUriString(builder.ToString());
6569
}
6670

67-
static readonly HttpClient httpClient = new HttpClient();
68-
6971
/// <summary>
7072
/// The maximum amount of times to retry getting a token.
7173
/// <para/>
@@ -85,26 +87,32 @@ public override string GetUri()
8587
/// <param name="refreshToken">This needs to be defined if "grantType" is "refresh_token".</param>
8688
/// <param name="currentRetries">Does not need to be defined. Used internally for retry attempt recursion.</param>
8789
/// <returns>Attempts to return a full <see cref="Token"/>, but after retry attempts, may return a <see cref="Token"/> with no <see cref="Token.AccessToken"/>, or null.</returns>
88-
async Task<Token> GetToken(string grantType, string authorizationCode = "", string refreshToken = "", int currentRetries = 0)
90+
async Task<Token> GetToken(string grantType, string authorizationCode = "", string refreshToken = "",
91+
int currentRetries = 0)
8992
{
90-
var content = new FormUrlEncodedContent(new Dictionary<string, string>
91-
{
92-
{ "grant_type", grantType },
93-
{ "code", authorizationCode },
94-
{ "refresh_token", refreshToken }
95-
});
93+
FormUrlEncodedContent content = new FormUrlEncodedContent(new Dictionary<string, string>
94+
{
95+
{"grant_type", grantType},
96+
{"code", authorizationCode},
97+
{"refresh_token", refreshToken}
98+
});
9699

97100
try
98101
{
99-
var siteResponse = await httpClient.PostAsync(exchangeServerUri, content);
102+
HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig);
103+
HttpClient client = new HttpClient(handler);
104+
HttpResponseMessage siteResponse = await client.PostAsync(_exchangeServerUri, content);
105+
100106
Token token = JsonConvert.DeserializeObject<Token>(await siteResponse.Content.ReadAsStringAsync());
101107
// Don't need to check if it was null - if it is, it will resort to the catch block.
102108
if (!token.HasError() && !string.IsNullOrEmpty(token.AccessToken))
103109
{
104110
return token;
105111
}
106112
}
107-
catch { }
113+
catch
114+
{
115+
}
108116

109117
if (currentRetries >= MaxGetTokenRetries)
110118
{
@@ -120,7 +128,8 @@ async Task<Token> GetToken(string grantType, string authorizationCode = "", stri
120128
}
121129
}
122130

123-
System.Timers.Timer accessTokenExpireTimer;
131+
System.Timers.Timer _accessTokenExpireTimer;
132+
124133
/// <summary>
125134
/// When Spotify authorization has expired. Will only trigger if <see cref="TimeAccessExpiry"/> is true.
126135
/// </summary>
@@ -134,19 +143,19 @@ void SetAccessExpireTimer(Token token)
134143
{
135144
if (!TimeAccessExpiry) return;
136145

137-
if (accessTokenExpireTimer != null)
146+
if (_accessTokenExpireTimer != null)
138147
{
139-
accessTokenExpireTimer.Stop();
140-
accessTokenExpireTimer.Dispose();
148+
_accessTokenExpireTimer.Stop();
149+
_accessTokenExpireTimer.Dispose();
141150
}
142151

143-
accessTokenExpireTimer = new System.Timers.Timer
152+
_accessTokenExpireTimer = new System.Timers.Timer
144153
{
145154
Enabled = true,
146155
Interval = token.ExpiresIn * 1000,
147156
AutoReset = false
148157
};
149-
accessTokenExpireTimer.Elapsed += (sender, e) => OnAccessTokenExpired?.Invoke(this, EventArgs.Empty);
158+
_accessTokenExpireTimer.Elapsed += (sender, e) => OnAccessTokenExpired?.Invoke(this, EventArgs.Empty);
150159
}
151160

152161
/// <summary>
@@ -161,6 +170,7 @@ public async Task<Token> ExchangeCodeAsync(string authorizationCode)
161170
{
162171
SetAccessExpireTimer(token);
163172
}
173+
164174
return token;
165175
}
166176

@@ -176,6 +186,7 @@ public async Task<Token> RefreshAuthAsync(string refreshToken)
176186
{
177187
SetAccessExpireTimer(token);
178188
}
189+
179190
return token;
180191
}
181192
}
@@ -204,7 +215,7 @@ public Task<bool> GetAuth()
204215
Code = code,
205216
Error = error
206217
}));
207-
return HttpContext.HtmlResponseAsync(((TokenSwapAuth)auth).HtmlResponse);
218+
return HttpContext.HtmlResponseAsync(((TokenSwapAuth) auth).HtmlResponse);
208219
}
209220
}
210-
}
221+
}

SpotifyAPI.Web/ProxyConfig.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Net;
3+
using System.Net.Http;
34

45
namespace SpotifyAPI.Web
56
{
@@ -73,5 +74,24 @@ public WebProxy CreateWebProxy()
7374

7475
return proxy;
7576
}
77+
78+
public static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null)
79+
{
80+
HttpClientHandler clientHandler = new HttpClientHandler
81+
{
82+
PreAuthenticate = false,
83+
UseDefaultCredentials = true,
84+
UseProxy = false
85+
};
86+
87+
if (string.IsNullOrWhiteSpace(proxyConfig?.Host)) return clientHandler;
88+
WebProxy proxy = proxyConfig.CreateWebProxy();
89+
clientHandler.UseProxy = true;
90+
clientHandler.Proxy = proxy;
91+
clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials;
92+
clientHandler.PreAuthenticate = proxy.UseDefaultCredentials;
93+
94+
return clientHandler;
95+
}
7696
}
7797
}

SpotifyAPI.Web/SpotifyWebClient.cs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal class SpotifyWebClient : IClient
2020

2121
public SpotifyWebClient(ProxyConfig proxyConfig = null)
2222
{
23-
HttpClientHandler clientHandler = CreateClientHandler(proxyConfig);
23+
HttpClientHandler clientHandler = ProxyConfig.CreateClientHandler(proxyConfig);
2424
_client = new HttpClient(clientHandler);
2525
}
2626

@@ -200,24 +200,5 @@ private void AddHeaders(Dictionary<string,string> headers)
200200
_client.DefaultRequestHeaders.TryAddWithoutValidation(headerPair.Key, headerPair.Value);
201201
}
202202
}
203-
204-
private static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null)
205-
{
206-
HttpClientHandler clientHandler = new HttpClientHandler
207-
{
208-
PreAuthenticate = false,
209-
UseDefaultCredentials = true,
210-
UseProxy = false
211-
};
212-
213-
if (string.IsNullOrWhiteSpace(proxyConfig?.Host)) return clientHandler;
214-
WebProxy proxy = proxyConfig.CreateWebProxy();
215-
clientHandler.UseProxy = true;
216-
clientHandler.Proxy = proxy;
217-
clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials;
218-
clientHandler.PreAuthenticate = proxy.UseDefaultCredentials;
219-
220-
return clientHandler;
221-
}
222203
}
223204
}

0 commit comments

Comments
 (0)