Authenticator
public protocol Authenticator : AnyObject, Sendable
Types adopting the Authenticator protocol can be used to authenticate URLRequests with an
AuthenticationCredential as well as refresh the AuthenticationCredential when required.
-
The type of credential associated with the
Authenticatorinstance.Declaration
Swift
associatedtype Credential : AuthenticationCredential, Sendable -
Applies the
Credentialto theURLRequest.In the case of OAuth2, the access token of the
Credentialwould be added to theURLRequestas a Bearer token to theAuthorizationheader.Declaration
Swift
func apply(_ credential: Credential, to urlRequest: inout URLRequest)Parameters
credentialThe
Credential.urlRequestThe
URLRequest. -
Refreshes the
Credentialand executes thecompletionclosure with theResultonce complete.Refresh can be called in one of two ways. It can be called before the
Requestis actually executed due to arequiresRefreshreturningtrueduring the adapt portion of theRequestcreation process. It can also be triggered by a failedRequestwhere the authentication server denied access due to an expired or invalidated access token.In the case of OAuth2, this method would use the refresh token of the
Credentialto generate a newCredentialusing the authentication service. Once complete, thecompletionclosure should be called with the newCredential, or the error that occurred.In general, if the refresh call fails with certain status codes from the authentication server (commonly a 401), the refresh token in the
Credentialcan no longer be used to generate a validCredential. In these cases, you will need to reauthenticate the user with their username / password.Please note, these are just general examples of common use cases. They are not meant to solve your specific authentication server challenges. Please work with your authentication server team to ensure your
Authenticatorlogic matches their expectations.Declaration
Swift
func refresh(_ credential: Credential, for session: Session, completion: @escaping @Sendable (Result<Credential, any Error>) -> Void)Parameters
credentialThe
Credentialto refresh.sessionThe
Sessionrequiring the refresh.completionThe closure to be executed once the refresh is complete.
-
Determines whether the
URLRequestfailed due to an authentication error based on theHTTPURLResponse.If the authentication server CANNOT invalidate credentials after they are issued, then simply return
falsefor this method. If the authentication server CAN invalidate credentials due to security breaches, then you will need to work with your authentication server team to understand how to identify when this occurs.In the case of OAuth2, where an authentication server can invalidate credentials, you will need to inspect the
HTTPURLResponseor possibly theErrorfor when this occurs. This is commonly handled by the authentication server returning a 401 status code and some additional header to indicate an OAuth2 failure occurred.It is very important to understand how your authentication server works to be able to implement this correctly. For example, if your authentication server returns a 401 when an OAuth2 error occurs, and your downstream service also returns a 401 when you are not authorized to perform that operation, how do you know which layer of the backend returned you a 401? You do not want to trigger a refresh unless you know your authentication server is actually the layer rejecting the request. Again, work with your authentication server team to understand how to identify an OAuth2 401 error vs. a downstream 401 error to avoid endless refresh loops.
Declaration
Swift
func didRequest(_ urlRequest: URLRequest, with response: HTTPURLResponse, failDueToAuthenticationError error: any Error) -> BoolParameters
urlRequestThe
URLRequest.responseThe
HTTPURLResponse.errorThe
Error.Return Value
trueif theURLRequestfailed due to an authentication error,falseotherwise. -
Determines whether the
URLRequestis authenticated with theCredential.If the authentication server CANNOT invalidate credentials after they are issued, then simply return
truefor this method. If the authentication server CAN invalidate credentials due to security breaches, then read on.When an authentication server can invalidate credentials, it means that you may have a non-expired credential that appears to be valid, but will be rejected by the authentication server when used. Generally when this happens, a number of requests are all sent when the application is foregrounded, and all of them will be rejected by the authentication server in the order they are received. The first failed request will trigger a refresh internally, which will update the credential, and then retry all the queued requests with the new credential. However, it is possible that some of the original requests will not return from the authentication server until the refresh has completed. This is where this method comes in.
When the authentication server rejects a credential, we need to check to make sure we haven’t refreshed the credential while the request was in flight. If it has already refreshed, then we don’t need to trigger an additional refresh. If it hasn’t refreshed, then we need to refresh.
Now that it is understood how the result of this method is used in the refresh lifecycle, let’s walk through how to implement it. You should return
truein this method if theURLRequestis authenticated in a way that matches the values in theCredential. In the case of OAuth2, this would mean that the Bearer token in theAuthorizationheader of theURLRequestmatches the access token in theCredential. If it matches, then we know theCredentialwas used to authenticate theURLRequestand should returntrue. If the Bearer token did not match the access token, then you should returnfalse.Declaration
Swift
func isRequest(_ urlRequest: URLRequest, authenticatedWith credential: Credential) -> BoolParameters
urlRequestThe
URLRequest.credentialThe
Credential.Return Value
trueif theURLRequestis authenticated with theCredential,falseotherwise.
View on GitHub
Install in Dash