Route HTTP requests through KnoxProxy using Apple's built-in URLSession. Works on iOS, macOS, tvOS, and watchOS with no external dependencies.
Set up URLSessionConfiguration with KnoxProxy connection details.
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: "gw.knoxproxy.com",
kCFNetworkProxiesHTTPPort: 7000,
kCFStreamPropertyHTTPSProxyHost: "gw.knoxproxy.com",
kCFStreamPropertyHTTPSProxyPort: 7000,
]Initialize a session with the proxy configuration.
let session = URLSession(configuration: config)Send a GET request through KnoxProxy.
let url = URL(string: "https://httpbin.org/ip")!
let task = session.dataTask(with: url) { data, response, error in
if let data = data {
print(String(data: data, encoding: .utf8) ?? "")
}
}
task.resume()Handle 407 challenges with a URLSessionDelegate.
class ProxyDelegate: NSObject, URLSessionDelegate {
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
let credential = URLCredential(
user: "USER",
password: "PASS",
persistence: .forSession
)
completionHandler(.useCredential, credential)
} else {
completionHandler(.performDefaultHandling, nil)
}
}
}
let session = URLSession(
configuration: config,
delegate: ProxyDelegate(),
delegateQueue: nil
)Target a specific country by changing the proxy username.
// In the delegate, change the username:
let credential = URLCredential(
user: "USER-country-gb",
password: "PASS",
persistence: .forSession
)Use modern Swift concurrency with the proxied session.
let (data, response) = try await session.data(from: url)
let httpResponse = response as! HTTPURLResponse
print("Status: \(httpResponse.statusCode)")
print(String(data: data, encoding: .utf8) ?? "")import Foundation
class ProxyDelegate: NSObject, URLSessionDelegate {
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
let credential = URLCredential(
user: "USER", password: "PASS", persistence: .forSession
)
completionHandler(.useCredential, credential)
}
}
let config = URLSessionConfiguration.default
config.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: "gw.knoxproxy.com",
kCFNetworkProxiesHTTPPort: 7000,
kCFStreamPropertyHTTPSProxyHost: "gw.knoxproxy.com",
kCFStreamPropertyHTTPSProxyPort: 7000,
]
let session = URLSession(
configuration: config, delegate: ProxyDelegate(), delegateQueue: nil
)
let url = URL(string: "https://httpbin.org/ip")!
let task = session.dataTask(with: url) { data, _, error in
if let data = data {
print(String(data: data, encoding: .utf8) ?? "")
} else if let error = error {
print("Error: \(error.localizedDescription)")
}
}
task.resume()
RunLoop.main.run(until: Date(timeIntervalSinceNow: 10))Each URLSession task gets a fresh exit IP. For sticky sessions, set the username to USER-session-{id} in the delegate credential.
| Problem | Fix |
|---|---|
| NSURLErrorDomain Code=-1012 (authentication required) | Implement urlSession(_:didReceive:completionHandler:) in your URLSessionDelegate and return the proxy credential. |
| NSURLErrorDomain Code=-1004 (could not connect) | Verify gw.knoxproxy.com:7000 is reachable. Check that connectionProxyDictionary uses the correct key constants. |
USER-country-de-city-berlin-session-profile07Order matters -- geo flags before the session flag. The session name is free text; use the profile ID so the mapping is self-documenting. Password stays as issued; no flags belong there. HTTP on :7000, SOCKS5 on :7001, same credentials.
Yes, on macOS. Set kCFStreamPropertySOCKSProxyHost and kCFStreamPropertySOCKSProxyPort in connectionProxyDictionary with port 7001.
Yes. Create the proxied URLSession once and call try await session.data(from: url) in any async context.
Each new dataTask gets a fresh IP by default. Avoid connection reuse by creating a new URLSessionConfiguration per request if needed.
Yes. URLSession respects connectionProxyDictionary on both Wi-Fi and cellular. IP allowlisting is not practical on mobile; use username/password auth.
Free trial on rotating residential -- 5 minutes setup, no credit card.