URLSession with credential

Hello!!

I would like to get data from server, but credential (username, password. Not Basi Authentification) is necessary to get it. Therefore, I try to use URLSession with URLCredential as following: https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge

However, I could not understand this document... So could you tell me how to use URLSession with URLCredential?

but credential (username, password. Not Basi Authentification) is necessary to get it.

What type of challenge are you working with?

Dear meaton,

Thank you so much for your comment!! (And I am so sorry for my previous wrong comment)

Now, I am making an application to visualize some vital data from a smart ring. Then, to get data, I tried URLSession like:

func startLoad() {
  let url = URL(string: "https://www.abcde-test-url.com/")!
  let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
      print("client error: \(error.localizedDescription)")
      return
    }
    guard let data = data, let response = response as? HTTPURLResponse else {
      print("no data or no response")
      return
    }
    if response.statusCode == 200 {
      print(data)
    } else {
      print("error status code: \(response.statusCode)")
    }
  }
  task.resume()
}

But, when I get the data from the smart ring server, I have to log in the smart-ring maker's website firstly. Therefore, I would like to use URLCredential for automatic log-in.

So I read the article but I couldn't understand the usage with URLCredential. In the official article, an description as "Implement the delegate methods described..." is written. However, I don't know the way how should I use the delegate method to use URLCredential. I am so sorry for my poor skill...

However, I don't know the way how should I use the delegate method to use URLCredential.

No problem at all. Here is a very bare-bones example that you could try out. NOTE: I just coded this up as is and you'll need to work it into your project as it makes sense, but the concepts are there. Also note that this example takes advantage of a session level challenge delegate for URLSessionDelegate but the same can be applied for a task level delegate as noted.

class YourNetworkMangerClass: NSObject {

	private var session: URLSession!
	private var sessionTask: URLSessionTask?
	private var readData = Data()
	...

	init() {
		let config = URLSessionConfiguration.default
		self.session = URLSession(configuration: config, delegate: self, delegateQueue: yourQueue)
	}

	public func sendRequest() {

		// Build the URLRequest as request.
		let task = self.session.dataTask(with: request)
		self.sessionTask = task
		task.resume()
	}
}

// This handles a challege at the session level via: `URLSessionDelegate`
// This can also be done at the task-level with: `URLSessionTaskDelegate`

extension YourNetworkMangerClass : URLSessionDelegate {
	func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
		if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
			// For Basic authentication.  Get your username and password from the Keychain or by another secure saved storage mechanism.
			let username = "YourUsername"
			let password = "YourPassword"
			let credential = URLCredential(user: username, password: password,
										   persistence: .forSession)
			completionHandler(.useCredential, credential)
		} else {
			// Provide a default fallback here
			completionHandler(.performDefaultHandling, nil)
		}
	}
}

extension YourNetworkMangerClass : URLSessionTaskDelegate {
	func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
		// The completion of your request
	}
}

extension YourNetworkMangerClass : URLSessionDataDelegate {
	func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
		self.readData += data // Concat your incoming data
	}
}

Dear meaton,

Thank you for your kindful example!! I do not know why my previous reply was disappeared but I am so sorry for this so much late reply.

I tried your example but I could not get data from server... Now, I tested as followings. Then I got a log in html but I could not log in the website. I guess NSURLAuthenticationMethodServerTrust means SSL/TLS so I mistook the usage of urlSession. If you have a time, is it OK you tell me your opinion?

extension NetworkManagerClass : URLSessionDelegate {
  func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
      // For Basic authentication. Get your username and password from the Keychain or by another secure saved storage mechanism.
      print("Basic")
      completionHandler(.useCredential, credential)
    } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
      print("1. Arrived Here")
      let username = "username"
      let password = "password"
      let credential = URLCredential(user: username, password: password, persistence: .forSession)
      completionHandler(.useCredential, credential)
    } else {
      print("else")
      print(challenge.protectionSpace.authenticationMethod)
      // Provide a default fallback here
      completionHandler(.performDefaultHandling, nil)
    }
  }
}

extension NetworkManagerClass : URLSessionTaskDelegate {
  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    // The completion of your request
    print("3. Should I log in here?")
}

extension NetworkManagerClass2 : URLSessionDataDelegate {
  func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    self.readData += data // Concat your incoming data
    print("2. get a log-in html")
    let string = String(data: data, encoding: .utf8)
    print(string ?? "none") // -> show log-in html
  }
}
URLSession with credential
 
 
Q