Use the information in this topic to migrate authentication code and programming patterns implemented in your existing ArcGIS Runtime SDK for Android (100.x) applications to the ArcGIS Maps SDK for Kotlin (200.x). There are two approaches to handling authentication:
- Default authentication handling. If you developed applications that adopted the default authentication challenge handler, offered by the ArcGIS Runtime SDK for Android (100.x), 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 Android, 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 Android (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 ArcGIS Maps SDK for Kotlin. Instead, you have these two options for handling authentication challenges in your application:
-
Use the Authenticator component, provided by the ArcGIS Maps SDK for Kotlin 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.
-
Set up an
ArcGISAuthenticationChallengeHandlerandNetworkAuthenticationChallengeHandlerto 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. With ArcGIS Maps SDK for Kotlin, you can obtain this directly from the ArcGISEnvironment.
ArcGISEnvironment.authenticationManagerAuthenticationManager()Authentication challenge handlers
ArcGIS and network authentication challenges were previously handled using a single AuthenticationChallengeHandler. With ArcGIS Maps SDK for Kotlin, 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.
// ArcGIS authentication challenge handlerArcGISEnvironment.authenticationManager.arcGISAuthenticationChallengeHandler = ArcGISAuthenticationChallengeHandler { challenge -> // If OAuth user configuration is available for the challenge then create `OAuthUserCredential` if (oAuthConfiguration.canBeUsedForUrl(challenge.requestUrl)) { // prompt to open browser and sign in with OAuth username and password // ... ArcGISAuthenticationChallengeResponse .ContinueWithCredential(oAuthUserCredential) } else { // ... // Prompt user for getting the username and password to create the `TokenCredential` // ... // Create TokenCredential val tokenCredential = TokenCredential.createWithChallenge(challenge,username, password, 30).getOrNull() tokenCredential?.let { ArcGISAuthenticationChallengeResponse.ContinueWithCredential(it) } ?: ArcGISAuthenticationChallengeResponse.ContinueAndFail } }
// Network authentication challenge handlerArcGISEnvironment.authenticationManager.networkAuthenticationChallengeHandler = NetworkAuthenticationChallengeHandler { authenticationChallenge -> when (authenticationChallenge.networkAuthenticationType) { is NetworkAuthenticationType.UsernamePassword -> // create the Password Credential val credential = PasswordCredential(username, password) NetworkAuthenticationChallengeResponse.ContinueWithCredential(credential) is NetworkAuthenticationType.ServerTrust -> NetworkAuthenticationChallengeResponse.ContinueWithCredential(ServerTrust) is NetworkAuthenticationType.Certificate -> { val selectedAlias = showCertificatePicker(activityContext) selectedAlias?.let { NetworkAuthenticationChallengeResponse.ContinueWithCredential(CertificateCredential(it)) } ?: NetworkAuthenticationChallengeResponse.ContinueAndFail } }}private class CustomChallengeHandler implements AuthenticationChallengeHandler {
@Override public AuthenticationChallengeResponse handleChallenge(AuthenticationChallenge challenge) { // handle authentication challenge by calling appropriate function on `challenge` object return new AuthenticationChallengeResponse( AuthenticationChallengeResponse.Action.CONTINUE_WITH_CREDENTIAL, challenge); }}
AuthenticationManager.setAuthenticationChallengeHandler(new CustomChallengeHandler());Credentials
ArcGIS Runtime SDK for Android handled a variety of credentials using the Credential and OAuthConfiguration classes. ArcGIS Maps SDK for Kotlin 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 Kotlin application, use OAuthUserCredential to handle OAuth authentication challenges. Previously, these challenges were handled by adding an OAuth user configuration to the authentication manager.
// Define OAuthConfigurationprivate val oAuthConfiguration = OAuthUserConfiguration( "<portal URL>", "<ClientID>", "<redirectURI>")
// Create OAuthUserCredential by passing OAuthConfiguration and initiate OAuth sign in process by invoking the provided startSignIn lambdaval oAuthUserCredential = OAuthUserCredential.create(oAuthConfiguration) { oAuthUserSignIn -> promptForOAuthUserSignIn(oAuthUserSignIn)}.getOrThrow()OAuthConfiguration configuration = new OAuthConfiguration(url, clientId, redirectUri);AuthenticationManager.addOAuthConfiguration(configuration);Token
scope.launch { var tokenCredential = TokenCredential.create(requestUrl,username, password, 30).getOrNull()}UserCredential credential = new UserCredential("<username>", "<password>");Pregenerated token
var accessToken = "xxxxxxx"val tokenInfo = TokenInfo(accessToken, Instant.now().plus(2, ChronoUnit.HOURS), true)var pregeneratedTokenCredential = PregeneratedTokenCredential(requestUrl, tokenInfo)// Pregenerated Token credential with token/refererUserCredential credential = UserCredential.createFromToken("token", "referer");Client-side certificate
private suspend fun showCertificatePicker(activityContext: Activity): String? = suspendCancellableCoroutine { continuation -> val aliasCallback = KeyChainAliasCallback { alias -> continuation.resume(alias) } KeyChain.choosePrivateKeyAlias( activityContext, aliasCallback, null, null, null, null ) }
val selectedAlias = showCertificatePicker(activityContext)
var certificateCredential = selectedAlias?.let { CertificateCredential(it) } ?: null// Client certificate credentialCertificateCredential certificateCredential = CertificateCredential("<certificate_path>", "certificate_password");Username and password
var passwordCredential = PasswordCredential("username", "password")UserCredential credential = new UserCredential("<username>", "<password>");Trust servers
Previously, you could avoid server trust challenges using the methods AuthenticationManager.setTrustAllSigners and AuthenticationManager.setSelfSignedCertificateListener. With ArcGIS Maps SDK for Kotlin, there is no direct replacement for these methods. You now create 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.
var trustCredential = NetworkCredential.serverTrustAuthenticationManager.setTrustAllSigners(true);
AuthenticationManager.setSelfSignedCertificateListener(selfSignedCertificateListener);Store and persist credentials
ArcGIS and network credentials were previously held in a single AGSCredentialCache. With ArcGIS Maps SDK for Kotlin, the authentication manager has separate credential stores that exist for the lifetime of the application. These are ArcGISCredentialStore and NetworkCredentialStore.
ArcGISEnvironment.authenticationManager.arcGISCredentialStoreArcGISEnvironment.authenticationManager.networkCredentialStoreAuthenticationManager.CredentialCache;To persist the credential stores in the Android Keystore, call the function createWithPersistence() when you make the credential store.
lifecycleScope.launch { val arcGISCredentialStore = ArcGISCredentialStore.createWithPersistence().getOrThrow() ArcGISEnvironment.authenticationManager.arcGISCredentialStore = arcGISCredentialStore
val networkCredentialStore = NetworkCredentialStore.createWithPersistence().getOrThrow() ArcGISEnvironment.authenticationManager.networkCredentialStore = networkCredentialStore}AuthenticationManager.CredentialCache.setPersistence(credentialPersistence)Previously, you could create and set a credential preemptively on a specific object. With ArcGIS Maps SDK for Kotlin, you must add the credential to the store before any secure resources are loaded.
var credential = TokenCredential.create(requestUrl,username, password, 30).getOrNull()credential?.let { // Preemptively add the credential to the store ArcGISEnvironment.authenticationManager.arcGISCredentialStore.add(it) var portal = Portal(url = "https://www.arcgis.com", Portal.Connection.Authenticated) portal.load()}// Set credential preemptively on the specific object before loading.UserCredential credential = UserCredential("<username>", "<password>");Portal portal = new Portal("https://www.arcgis.com");portal.setCredential(credential);portal.loadAsync();portal.addDoneLoadingListener(new Runnable() { @Override public void run() { // handle success or failure }});