Respond appropriately when a server demands authentication for a URL request.
When your app makes a request with a
URLSession, the server may respond with one or more demands for credentials before continuing. The session task attempts to handle this for you. If it can’t, it calls your session’s
delegate to handle the challenges.
Implement the delegate methods described in this article to answer challenges issued by a server that your app connects to. If you don’t implement a delegate, your request may be denied by the server, and you receive a response with HTTP status code
401 (Forbidden) instead of the data you expect.
Determine the Appropriate Delegate Method
Implement one or both delegate authentication methods, depending on the nature of the challenge(s) you receive.
Session(_: did Receive: completion Handler:)
URLSessionto handle session-wide challenges. These are challenges like Transport Layer Security (TLS) validation. Once you’ve successfully handled this kind of challenge, your action remains in effect for all tasks created from that
Session(_: task: did Receive: completion Handler:)
URLSessionto handle task-specific challenges. These are challenges like demands for username/password authentication. Each task created from a given session may issue its own challenges.
As a simple example, consider what happens when you request an
http URL protected by HTTP Basic authentication, as defined in RFC 7617. Because this is a task-specific challenge, you handle this by implementing
Figure 1 outlines a strategy for responding to the HTTP Basic challenge.
The following sections implement this strategy.
Determine the Type of Authentication Challenge
When you receive an authentication challenge, use your delegate method to determine the type of challenge. The delegate method receives a
URLAuthentication instance that describes the challenge being issued. This instance contains a
protection property whose
authentication property indicates the kind of challenge being issued (such as a request for a username and password, or a client certificate). You use this value to determine whether you can handle the challenge.
You respond to the challenge by directly invoking the completion handler passed in to the challenge, passing an
URLSession indicating your response to the challenge. You use the disposition argument to provide a credential, cancel the request, or allow the default handling to proceed, whichever is appropriate.
Listing 1 tests the authentication method to see if it is the expected type, HTTP Basic. If the
authentication property indicates some other kind of challenge, it calls the completion handler with the
URLSession disposition. Telling the task to use its default handling may satisfy the challenge; otherwise, the task will move on to the next challenge in the response and call this delegate again. This process continues until the task reaches the HTTP Basic challenge that you expect to handle.
Create a Credential Instance
To successfully answer the challenge, you need to submit a credential appropriate to type of challenge you have received. For HTTP Basic and HTTP Digest challenges, you provide a username and password. Listing 2 shows a helper method that attempts to create a
URLCredential instance from user-interface fields, if they are filled in.
In this example, the returned
URLCredential persistence, so it’s only stored by the
URLSession instance that created the task. You would need to supply new
URLCredential instances for tasks created by other session instances, and on future runs of the app.
Call the Completion Handler
Once you’ve tried to create a credential instance, you must call the completion handler to answer the challenge.
If you can’t create a credential, or if the user explicitly canceled, call the completion handler and pass the
.Auth Challenge Disposition .cancel Authentication Challenge
If you can create a credential instance, use the
URLSessiondisposition to pass it to the completion handler.
.Auth Challenge Disposition .use Credential
Listing 3 shows both these options.
If you supply a credential that is accepted by the server, the task begins uploading or downloading data.
Handle Failures Gracefully
If the credential is refused, the system calls your delegate method again. When this happens, the callback provides your rejected credential as the
proposed property of the
URLAuthentication parameter. The challenge instance also includes a
previous property, which indicates how many times the credential has been rejected. You can use these properties to determine what to do next. For example, if the
previous is greater than zero, you could use the user string of the
proposed to populate a user/password reentry UI.