URLProtocol for Bearer Authentication?

I'm trying to use URLProtocol for implementing JWT authentication.


The authentication flow would look like this:

A request ist sent to the server. If the server returns 401 (WWW-Authenticate: Bearer realm="example.com"') the user needs to provide his credentials. With those credentials a request to the authentication server will return a valid access token. This access token is then used for the original request by setting a custom header.


There are multiple issues I'm facing:


  1. didReceive challenge: URLAuthenticationChallenge, completionHandler is not called with Bearer authenticateion
  2. inside didReceive challenge: URLAuthenticationChallenge, completionHandler I don't find any way to append the header to the original request
  3. if the user takes longer to provide his credentials than the timeout of the original request, the request would run into an timeout


Is seems that there is no way to use URLProtocol for handling token based authentication, is it?


Is there any alternative suggested way to handle bearer authentication without using frameworks like Alamofire or Moya?

I presume you’re doing this recursively, that is, your

URLProtocol
subclass is calling
URLSession
to actually do the networking on the wire, as shown by the CustomHTTPProtocol sample code.

If so, I recommend against this.

URLProtocol
subclasses are useful for some things, but it’s best to avoid them if you can. Specifically, if you control the code making the original requests (presumably via
URLSession
) then you should modify that code to handle authentication rather than trying to do it via a recursive
URLProtocol
subclass. Recursive
URLProtocol
subclasses are complex, bug prone, and lead you far off the beaten path.

Modifying your client code to do this does not mean that you have to adopt some large blob of third-party code. Just wrap your

URLSession
tasks in a lightweight wrapper that:
  1. Traps the ‘unauthorised’ response

  2. Talks to your credential acquisition subsystem to get the right header

  3. Retries the request with that header

Regardless of the above, I want to address some of your specific points:

1. didReceive challenge: URLAuthenticationChallenge, completionHandler is not called with Bearer authenticateion

Correct.

URLSession
will only generate authentication challenges for authentication methods that it knows about. It knows nothing about
Bearer
authentication and thus passes the 401 response back to the client.

We do have a bug on file requesting that

URLSession
support arbitrary authentication challenges (r. 26855589).

2. inside didReceive challenge: URLAuthenticationChallenge, completionHandler I don't find any way to append the header to the original request

Also correct. You will have to retry the request as I mentioned above.

3. if the user takes longer to provide his credentials than the timeout of the original request, the request would run into an timeout

The request timeout (

timeoutIntervalForRequest
) does not run while the session is waiting for an authentication challenge response. Then again, this won’t matter to you anyway because no authentication challenge is being generated anyway, so your retry will be considered a completely separate request.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

there is still no way to support OAuth2 using URLSession, correct?

Correct. Well, no good way. The standard workaround is to set the Authorization header directly, which is less than ideal.

I have a background upload and therefore cannot handle 401 by hand and just repeat the request.

Have you looked at -URLSession:task:willBeginDelayedRequest:completionHandler:?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

URLProtocol for Bearer Authentication?
 
 
Q