Use the information in this topic to migrate authentication code and programming patterns implemented in your existing ArcGIS Runtime SDK for iOS (100.x) applications to the ArcGIS Maps SDK for Swift (200.x). There are two main approaches for handling authentication:
- Default authentication handling. If you developed applications that adopted the default authentication challenge handler, offered by the ArcGIS Runtime SDK for iOS, see the Default handling of authentication challenges section.
- Custom authentication handling. If you developed your own custom authentication challenge handlers, using the ArcGIS Runtime SDK for iOS, see the specific migration steps in the authentication manager, authentication challenge handlers and credentials sections.
Default handling of authentication challenges
When you built an application with ArcGIS Runtime SDK for iOS (100.x) that accessed secured resources, the API used a default challenge handler that automatically displayed a login UI to the user. This UI presented information about the challenge as well as the appropriate options, such as username and password inputs. This default handler and UI are not available with the ArcGIS Maps SDK for Swift.
You have two options for handling authentication challenges in your ArcGIS Maps SDK for Swift application:
-
Use the Authenticator component, provided by the ArcGIS Maps SDK for Swift toolkit, to handle authentication challenges, such as ArcGIS authentication (token and OAuth), Integrated Windows Authentication (IWA), and Client Certificate (PKI). The component provides a default UI for login prompts, certificate selection prompts, and server trust prompts. For more information about setting up the tool, persisting credential stores, revoking tokens and clearing credentials, see the Authentication tool section in the security and authentication topic. To see the Authenticator in action, check out out the Authentication Example application and refer to
Authentication
in your project.App.swift -
Set up an
ArcGISAuthenticationChallengeHandler
andNetworkAuthenticationChallengeHandler
to capture the authentication challenges. Write your own code to present a UI with login prompts, certificate selection prompts, or server trust prompts. Use the response to create an appropriate credential so that the application can continue with the challenge. For more information, see Handle authentication challenges in the security and authentication topic.
Authentication manager
Access to secured resources is managed using the authentication manager, which you can now obtain directly from the ArcGISEnvironment
.
let authenticationManager = ArcGISEnvironment.authenticationManager
Authentication challenge handlers
ArcGIS and network authentication challenges were previously handled using a single AGS
. With ArcGIS Maps SDK for Swift, you must create separate authentication challenge handlers that respond to any ArcGISAuthenticationChallenge
or NetworkAuthenticationChallenge
. Set the ArcGIS and network authentication challenge handlers on the AuthenticationManager
.
@MainActor
// Creates an ArcGIS authentication challenge handler
final class MyArcGISChallengeHandler: ArcGISAuthenticationChallengeHandler {
// The OAuth configurations that this challenge handler can work with.
let oAuthUserConfigurations: [OAuthUserConfiguration]
public init(
oAuthUserConfigurations: [OAuthUserConfiguration] = []
) {
self.oAuthUserConfigurations = oAuthUserConfigurations
}
// Handles the challenge to an ArcGIS secured resource that requires OAuth or ArcGIS Token authentication.
func handleArcGISAuthenticationChallenge(
_ challenge: ArcGISAuthenticationChallenge
) async throws -> ArcGISAuthenticationChallenge.Disposition {
// If an OAuth user configuration is available for the challenge then create an `OAuthUserCredential`.
if let configuration = oAuthUserConfigurations.first(where: { $0.canBeUsed(for: challenge.requestURL) }) {
return .continueWithCredential(
try await OAuthUserCredential.credential(for: configuration)
)
} else {
// If not, prompt the user for a username and password to create a `TokenCredential`.
// ...
return .continueWithCredential(
try await TokenCredential.credential(for: challenge, username: "username", password: "password")
)
}
}
}
@MainActor
func createAndSetArcGISChallengeHandler() {
// Creates the challenge handler with desired OAuth user configurations and set it on the `AuthenticationManager`.
let myArcGISChallengeHandler = MyArcGISChallengeHandler(oAuthUserConfigurations: [OAuthUserConfiguration(portalURL: URL(string: "my-portal-URL")!, clientID: "my-client-ID", redirectURL: URL(string: "my-redirect-URL")!)])
ArcGISEnvironment.authenticationManager.arcGISAuthenticationChallengeHandler = myArcGISChallengeHandler
}
// Creates a Network authentication challenge handler
final class MyNetworkChallengeHandler: NetworkAuthenticationChallengeHandler {
func handleNetworkAuthenticationChallenge(
_ challenge: NetworkAuthenticationChallenge
) async -> NetworkAuthenticationChallenge.Disposition {
switch challenge.kind {
case .ntlm, .basic, .digest:
// Prompts the user for a username and password to create a `NetworkCredential`.
// ...
return .continueWithCredential(.password(username: "username", password: "password"))
case .clientCertificate:
// Prompts the user for a client certificate to create a `NetworkCredential`.
// ...
do {
return .continueWithCredential(try .certificate(at: URL(fileURLWithPath: "/pathToCertificate"), password: "password"))
} catch {
return .continueWithoutCredential
}
case .serverTrust:
// Prompts user to ask if they want to trust an untrusted host.
// ...
return .continueWithCredential(.serverTrust)
case .negotiate:
// Rejects the negotiate challenge so next authentication protection
// space is tried.
return .rejectProtectionSpace
@unknown default:
return .cancel
}
}
}
func createAndSetNetworkChallengeHandler() {
// Creates the challenge handler and set it on the `AuthenticationManager`.
let myNetworkChallengeHandler = MyNetworkChallengeHandler()
ArcGISEnvironment.authenticationManager.networkAuthenticationChallengeHandler = myNetworkChallengeHandler
}
Credentials
ArcGIS Runtime SDK for iOS handled a variety of credentials using the AGS
and AGSO
classes. ArcGIS Maps SDK for Swift uses a range of specialized credential types to match the ArcGIS credentials (OAuthUserCredential
, TokenCredential
, and PregeneratedTokenCredential
) and network credentials (CertificateCredential
and PasswordCredential
). You can write code in an authentication challenge handler to prompt the user for credential information, create a credential, and use it to continue with the challenge. This credential will be placed in the store and used by future requests coming from the same source.
You can also create ArcGIS credentials preemptively and store them in ArcGISCredentialStore
.
OAuth
In your ArcGIS Maps SDK for Swift application, use OAuthUserCredential
to handle OAuth authentication challenges for Portal
. Previously, these challenges were handled by adding an OAuth configuration (AGSO
) to the AGS
.
// OAuth credentials
let configuration = OAuthUserConfiguration(portalURL: portalURL, clientID: clientID, redirectURL: redirectURL)
let oAuthUserCredential = try await OAuthUserCredential.credential(for: configuration)
Token
// Token credential
let tokenCredential = try await TokenCredential.credential(for: myURL, username: "my-username", password: "my-password", tokenExpirationMinutes: expirationMinutes)
let tokenInfo = try await tokenCredential.tokenInfo
Pregenerated token
// Pregenerated token credential
guard let tokenInfo = TokenInfo(accessToken: accessToken, expirationDate: expirationDate, isSSLRequired: true) else { return }
let pregeneratedTokenCredential = PregeneratedTokenCredential(url: serviceURL, tokenInfo: tokenInfo, referer: referer)
Client-side certificate
// Client certificate credential
let certificateCredential = try NetworkCredential.certificate(at: fileURL, password: "my-password")
Username and password
// Password credential for HTTP Basic/Digest, Integrated Windows Authentication (IWA)
let passwordCredential = NetworkCredential.password(username: "my-username", password: "my-password")
Trust servers
Previously, you could avoid server trust challenges by preemptively adding the host to the AGS
collection. The ArcGIS Maps SDK for Swift now uses the NetworkCredential.serverTrust
to handle server trust challenges. If you handle a trust challenge with a credential, it will be placed in the store and used by future trust challenges.
// Server trust credential for host with self-signed certificate
let credential = NetworkCredential.serverTrust
Store and persist credentials
ArcGIS and network credentials were previously held in a single AGS
. With ArcGIS Maps SDK for Swift, the authentication manager has separate credential stores that exist for the lifetime of the application. These are ArcGISCredentialStore
and NetworkCredentialStore
.
let credentialStore = ArcGISEnvironment.authenticationManager.arcGISCredentialStore
let networkStore = ArcGISEnvironment.authenticationManager.networkCredentialStore
To make the credential stores persist in the keychain, set the store instances created using function make
on the authentication manager.
ArcGISEnvironment.authenticationManager.arcGISCredentialStore = try await .makePersistent(
access: .afterFirstUnlockThisDeviceOnly,
synchronizesWithiCloud: true
)
await ArcGISEnvironment.authenticationManager.setNetworkCredentialStore(
try await .makePersistent(access: .afterFirstUnlockThisDeviceOnly, synchronizesWithiCloud: true)
)
Previously, you could create and set a credential preemptively on a specific object. With ArcGIS Maps SDK for Swift, you can add the credential to the store before any secure resources are loaded.
let tokenCredential = try await TokenCredential.credential(
for: URL(string: "https://www.arcgis.com")!,
username: "username",
password: "password"
)
ArcGISEnvironment.authenticationManager.arcGISCredentialStore.add(tokenCredential)
let portal = Portal.arcGISOnline(connection: .authenticated)
try await portal.load()