How to implement RFC 7235 (HTTP Authentication) when Authorization is a reserved HTTP header?

We're developing a connectivity library for IoT devices. It should support authentication using a variant of RFC 7235 (HTTP Authentication).

From that specification:

"A user agent that wishes to authenticate itself with an origin server can do so by including an Authorization header field with the request."

To implement this feature we are executing (URLRequest's) setValue(..., forHTTPHeaderField: "Authorization") on our requests.

While that seems to work we are worried about this text about "Reserved HTTP headers" (which include the "Authorization" header) in the Apple documentation:

"If you set a value for one of these reserved headers, the system may ignore the value you set, or overwrite it with its own value, or simply not send it. Moreover, the exact behavior may change over time. To avoid confusing problems like this, do not set these headers directly."

So our approach is wrong?

How should we do this instead?
For Authorization with a HTTP Basic Auth challenge instead of setting the initial header you can also handle the authorization requests by using a URLCredential and URLProtectionSpace:

Code Block swift
let challengeCredential = URLCredential(user: "user", password: "password", persistence: .forSession)
let protectionSpace = URLProtectionSpace(host: "httpbin.org", port: 443, protocol: "https", realm: "Fake Realm", authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
URLCredentialStorage.shared.setDefaultCredential(challengeCredential, for: protectionSpace)


Or handle the challenge in a URLSessionTaskDelegate callback:

Code Block swift
extension MyClass: URLSessionTaskDelegate {
func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let authMethod = challenge.protectionSpace.authenticationMethod
guard authMethod == NSURLAuthenticationMethodHTTPBasic else {
completionHandler(.performDefaultHandling, nil)
return
}
let challengeCredential = URLCredential(user: "user", password: "password", persistence: .forSession)
completionHandler(.useCredential, challengeCredential)
}
}

Try this out with httpbin as a testbed.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thank you for answering Matt. Looks like I should have been more specific.

We're not using the 'Basic' HTTP Authentication Scheme from RFC 7617, but a custom challenge-response authentication scheme.

Our response to a challenge should be a HTTP header field "Authorization" with as value a string that combines these parts:
  1. The name of our custom scheme

  2. A space as a separator

  3. A value calculated using the challenge and a shared secret

(See Appendix C of RFC 7235 for the exact syntax)

This probably means we can't use URLCredential?

(and thus I'm still concerned about "Authorization" being a reserved HTTP header field)
You are correct. In a case where you need to handle a custom challenge, you will have no other choice other than setting the initial header directly on the URLRequest. I would open an enhancement request to further handle custom authentication challenges like this and follow up to this thread with the Feedback ID.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Submitted FB7834980.
Thanks. I see this internally and I have copied myself on it for further updates.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
How to implement RFC 7235 (HTTP Authentication) when Authorization is a reserved HTTP header?
 
 
Q